orizu 0.5.37 → 0.5.39
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 +18 -3
- package/dist/app-commands.d.ts.map +1 -1
- package/dist/app-commands.js +215 -57
- package/dist/app-publish-failure.d.ts +6 -0
- package/dist/app-publish-failure.d.ts.map +1 -0
- package/dist/app-publish-failure.js +9 -0
- package/dist/app-publish-paths.d.ts +4 -0
- package/dist/app-publish-paths.d.ts.map +1 -0
- package/dist/app-publish-paths.js +32 -0
- package/dist/app-publish-workspace.d.ts +16 -0
- package/dist/app-publish-workspace.d.ts.map +1 -0
- package/dist/app-publish-workspace.js +175 -0
- package/dist/artifacts-git-runtime.d.ts +5 -0
- package/dist/artifacts-git-runtime.d.ts.map +1 -1
- package/dist/artifacts-git-runtime.js +70 -25
- package/dist/artifacts-session-merge.d.ts +62 -0
- package/dist/artifacts-session-merge.d.ts.map +1 -0
- package/dist/artifacts-session-merge.js +123 -0
- package/dist/dataset-append-workflow.d.ts +12 -0
- package/dist/dataset-append-workflow.d.ts.map +1 -0
- package/dist/dataset-append-workflow.js +198 -0
- package/dist/dataset-commands.d.ts.map +1 -1
- package/dist/dataset-commands.js +11 -130
- package/dist/dataset-transfer-download.js +6 -6
- package/dist/dataset-transfer-upload.js +8 -8
- package/dist/git-credential.d.ts +1 -1
- package/dist/git-credential.d.ts.map +1 -1
- package/dist/git-credential.js +8 -1
- package/dist/help.js +3 -3
- package/dist/hosted-boot.d.ts +11 -0
- package/dist/hosted-boot.d.ts.map +1 -1
- package/dist/hosted-boot.js +46 -1
- package/dist/hosted-harvest.d.ts.map +1 -1
- package/dist/hosted-harvest.js +11 -1
- package/dist/hosted-session-cli.d.ts.map +1 -1
- package/dist/hosted-session-cli.js +6 -1
- package/dist/hosted-session-seed.d.ts +45 -0
- package/dist/hosted-session-seed.d.ts.map +1 -0
- package/dist/hosted-session-seed.js +61 -0
- package/dist/hosted-skill-staging.d.ts +8 -3
- package/dist/hosted-skill-staging.d.ts.map +1 -1
- package/dist/hosted-skill-staging.js +10 -3
- package/dist/jsonl-stream.d.ts +1 -0
- package/dist/jsonl-stream.d.ts.map +1 -1
- package/dist/jsonl-stream.js +7 -0
- package/dist/provider-list-workflow.d.ts +3 -0
- package/dist/provider-list-workflow.d.ts.map +1 -0
- package/dist/provider-list-workflow.js +95 -0
- package/dist/provider-wire-record.d.ts +3 -0
- package/dist/provider-wire-record.d.ts.map +1 -0
- package/dist/provider-wire-record.js +4 -0
- package/dist/providers-cli.d.ts.map +1 -1
- package/dist/providers-cli.js +5 -15
- package/dist/publish-merge-job.d.ts +68 -0
- package/dist/publish-merge-job.d.ts.map +1 -0
- package/dist/publish-merge-job.js +320 -0
- package/dist/publish-merge-timing.d.ts +18 -0
- package/dist/publish-merge-timing.d.ts.map +1 -0
- package/dist/publish-merge-timing.js +23 -0
- package/dist/workbench-cli.d.ts +4 -0
- package/dist/workbench-cli.d.ts.map +1 -1
- package/dist/workbench-cli.js +11 -1
- package/dist/workspace-bootstrap-job.d.ts +1 -0
- package/dist/workspace-bootstrap-job.d.ts.map +1 -1
- package/dist/workspace-bootstrap-job.js +1 -1
- package/package.json +5 -2
- package/src/app-commands.ts +234 -66
- package/src/app-publish-failure.ts +7 -0
- package/src/app-publish-paths.ts +27 -0
- package/src/app-publish-workspace.ts +207 -0
- package/src/artifacts-git-runtime.ts +73 -31
- package/src/artifacts-session-merge.ts +253 -0
- package/src/dataset-append-workflow.ts +205 -0
- package/src/dataset-commands.ts +10 -170
- package/src/dataset-transfer-download.ts +5 -5
- package/src/dataset-transfer-upload.ts +7 -7
- package/src/git-credential.ts +8 -1
- package/src/help.ts +3 -3
- package/src/hosted-boot.ts +56 -1
- package/src/hosted-harvest.ts +11 -1
- package/src/hosted-session-cli.ts +6 -1
- package/src/hosted-session-seed.ts +78 -0
- package/src/hosted-skill-staging.ts +11 -3
- package/src/jsonl-stream.ts +8 -0
- package/src/provider-list-workflow.ts +108 -0
- package/src/provider-wire-record.ts +4 -0
- package/src/providers-cli.ts +5 -13
- package/src/publish-merge-job.ts +350 -0
- package/src/publish-merge-timing.ts +27 -0
- package/src/workbench-cli.ts +15 -1
- package/src/workspace-bootstrap-job.ts +1 -1
- package/vendor/skills/orizu/flows/onboard.md +1 -1
- package/vendor/skills/orizu/references/authority-map.md +2 -2
- package/vendor/skills/orizu/references/building-apps.md +24 -0
- package/vendor/skills/orizu/references/cli-reference.md +13 -4
- package/vendor/skills/orizu/references/optimization-reports.md +1 -1
- package/vendor/skills/orizu/references/primer.md +1 -0
- package/vendor/skills/orizu/references/prompt-control-plane.md +9 -5
package/dist/hosted-boot.js
CHANGED
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
import { spawnSync } from 'child_process';
|
|
33
33
|
import { closeSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, unlinkSync, writeSync } from 'fs';
|
|
34
34
|
import { isValidCloudflareArtifactsGitRemote } from './cloudflare-artifacts-git-remote.js';
|
|
35
|
+
import { seedSessionCopy } from './hosted-session-seed.js';
|
|
35
36
|
import { AGENT_GIT_IDENTITY, BEARER_BASENAME, BOOT_CONTEXT_BASENAME, DEFAULT_CACHE_REFRESH_BUFFER_MS, HELPER_SCRIPT_BASENAME, REPO_CRED_CACHE_BASENAME, renderCredentialHelperScript, serializeBootContext, } from './hosted-runtime-assets.js';
|
|
36
37
|
import { INJECTED_ENV_VARS_ENV, closeHostedLoopSession, runHostedLoop, runHostedLoopTurn, startHostedLoopSession, } from './hosted-loop.js';
|
|
37
38
|
import { DEFAULT_EGRESS_CANARY_HOST, DEFAULT_HOSTED_MODEL } from './hosted-loop-lifecycle.js';
|
|
@@ -488,6 +489,23 @@ export async function beginRunExecution(opts) {
|
|
|
488
489
|
}
|
|
489
490
|
throw new Error(`run_started transition failed: ${detail}`);
|
|
490
491
|
}
|
|
492
|
+
/** Mint a `team_read` key (ORI-2280 B1) to learn this session's team copy, so
|
|
493
|
+
* the boot can fill an empty session copy from it (ORI-2118). The credential
|
|
494
|
+
* helper mints its own keys for the git commands; this one only names the
|
|
495
|
+
* remote and lapses on its own (300 s). */
|
|
496
|
+
export async function resolveTeamRemote(opts) {
|
|
497
|
+
const url = `${opts.baseUrl}/api/cli/workspaces/${encodeURIComponent(opts.workspaceId)}/repo-token`;
|
|
498
|
+
const minted = await bearerJson(opts.fetchImpl, url, opts.bearer, {
|
|
499
|
+
method: 'POST',
|
|
500
|
+
headers: { 'Content-Type': 'application/json' },
|
|
501
|
+
body: JSON.stringify({ purpose: 'team_read', sessionId: opts.sessionId }),
|
|
502
|
+
});
|
|
503
|
+
const remote = asString(minted.remote);
|
|
504
|
+
if (asString(minted.provider) !== 'cloudflare_artifacts' || !remote || !isValidCloudflareArtifactsGitRemote(remote)) {
|
|
505
|
+
throw new Error('team_read response carried no valid Artifacts remote');
|
|
506
|
+
}
|
|
507
|
+
return remote;
|
|
508
|
+
}
|
|
491
509
|
/** Mint a session_read repo token to learn the repo full name, then build the
|
|
492
510
|
* GitHub clone URL (mirrors the operator path's `defaultResolveRepo`). */
|
|
493
511
|
export async function resolveRepo(opts) {
|
|
@@ -526,6 +544,9 @@ export async function resolveRepo(opts) {
|
|
|
526
544
|
// reused after we read `repo` from it.
|
|
527
545
|
return { repoFullName, cloneUrl: `https://github.com/${repoFullName}.git` };
|
|
528
546
|
}
|
|
547
|
+
/** The credential-helper context for the team copy, used only to fill an
|
|
548
|
+
* empty session copy (ORI-2118). */
|
|
549
|
+
const TEAM_BOOT_CONTEXT_BASENAME = 'boot-team.json';
|
|
529
550
|
const defaultExec = (cmd, args, opts) => {
|
|
530
551
|
const res = spawnSync(cmd, args, { cwd: opts?.cwd, encoding: 'utf8' });
|
|
531
552
|
return { status: res.status ?? 1, stdout: res.stdout ?? '', stderr: res.stderr ?? '' };
|
|
@@ -762,9 +783,33 @@ export async function runHostedBoot(opts) {
|
|
|
762
783
|
cacheBufferMs: DEFAULT_CACHE_REFRESH_BUFFER_MS,
|
|
763
784
|
};
|
|
764
785
|
writeFile(bootContextAbs, serializeBootContext(bootContext));
|
|
786
|
+
const helperValue = `!node ${helperScriptAbs} ${bootContextAbs}`;
|
|
787
|
+
// 4b — ORI-2118: a hosted session's Artifacts copy is created empty (forks
|
|
788
|
+
// of a busy team copy cannot be cloned), so fill it from the team copy
|
|
789
|
+
// before the first clone. A copy that already has `main` is left alone.
|
|
790
|
+
if (isValidCloudflareArtifactsGitRemote(repo.cloneUrl)) {
|
|
791
|
+
const credentialConfig = (helper) => [`credential.helper=${helper}`, 'credential.useHttpPath=true'];
|
|
792
|
+
await seedSessionCopy({
|
|
793
|
+
exec,
|
|
794
|
+
sessionRemote: repo.cloneUrl,
|
|
795
|
+
sessionGitConfig: credentialConfig(helperValue),
|
|
796
|
+
scratchDir: `${sessionDirAbs}/seed.git`,
|
|
797
|
+
resolveTeam: async () => {
|
|
798
|
+
const teamRemote = await resolveTeamRemote({ baseUrl: env.baseUrl, workspaceId, sessionId: env.sessionId, bearer: bearer.token, fetchImpl });
|
|
799
|
+
assertSafeGitValue('teamRemote', teamRemote);
|
|
800
|
+
const teamContextAbs = `${sessionDirAbs}/${TEAM_BOOT_CONTEXT_BASENAME}`;
|
|
801
|
+
writeFile(teamContextAbs, serializeBootContext({
|
|
802
|
+
...bootContext,
|
|
803
|
+
repoFullName: teamRemote,
|
|
804
|
+
host: new URL(teamRemote).host.toLowerCase(),
|
|
805
|
+
tokenPurposes: { primary: 'team_read', fallback: 'team_read' },
|
|
806
|
+
}));
|
|
807
|
+
return { remote: teamRemote, gitConfig: credentialConfig(`!node ${helperScriptAbs} ${teamContextAbs}`) };
|
|
808
|
+
},
|
|
809
|
+
});
|
|
810
|
+
}
|
|
765
811
|
// 5 — Clone the session branch VIA the pull-mode credential helper (same
|
|
766
812
|
// invocation the operator path makes; no token in the URL/config).
|
|
767
|
-
const helperValue = `!node ${helperScriptAbs} ${bootContextAbs}`;
|
|
768
813
|
const clone = exec('git', [
|
|
769
814
|
'clone',
|
|
770
815
|
'--depth',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hosted-harvest.d.ts","sourceRoot":"","sources":["../src/hosted-harvest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAaH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAED,iFAAiF;AACjF,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,iBAAiB,CAAA;AAExE,MAAM,WAAW,cAAc;IAC7B,iFAAiF;IACjF,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,0EAA0E;IAC1E,aAAa,EAAE,MAAM,CAAA;IACrB,+DAA+D;IAC/D,gBAAgB,EAAE,MAAM,CAAA;IACxB,mFAAmF;IACnF,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,0EAA0E;IAC1E,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IACvC,kFAAkF;IAClF,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACtC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,qEAAqE;IACrE,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,oBAAoB,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAElD,eAAO,MAAM,mCAAmC,0GAItC,CAAA;AAEV,eAAO,MAAM,iCAAiC,+EAGpC,CAAA;AAEV,eAAO,MAAM,+BAA+B;;;;CAgBlC,CAAA;AAUV,wBAAgB,4BAA4B,CAC1C,UAAU,GAAE,SAAS,MAAM,EAAwC,GAClE,MAAM,GAAG,IAAI,CAEf;AA6GD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,cAAc,
|
|
1
|
+
{"version":3,"file":"hosted-harvest.d.ts","sourceRoot":"","sources":["../src/hosted-harvest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAaH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAED,iFAAiF;AACjF,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,iBAAiB,CAAA;AAExE,MAAM,WAAW,cAAc;IAC7B,iFAAiF;IACjF,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,0EAA0E;IAC1E,aAAa,EAAE,MAAM,CAAA;IACrB,+DAA+D;IAC/D,gBAAgB,EAAE,MAAM,CAAA;IACxB,mFAAmF;IACnF,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,0EAA0E;IAC1E,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IACvC,kFAAkF;IAClF,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACtC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,qEAAqE;IACrE,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,oBAAoB,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAElD,eAAO,MAAM,mCAAmC,0GAItC,CAAA;AAEV,eAAO,MAAM,iCAAiC,+EAGpC,CAAA;AAEV,eAAO,MAAM,+BAA+B;;;;CAgBlC,CAAA;AAUV,wBAAgB,4BAA4B,CAC1C,UAAU,GAAE,SAAS,MAAM,EAAwC,GAClE,MAAM,GAAG,IAAI,CAEf;AA6GD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,cAAc,CAmKrE"}
|
package/dist/hosted-harvest.js
CHANGED
|
@@ -235,10 +235,20 @@ export function harvestWorkspace(opts) {
|
|
|
235
235
|
}
|
|
236
236
|
const dirty = status.stdout.trim().length > 0;
|
|
237
237
|
if (dirty) {
|
|
238
|
-
|
|
238
|
+
// Add everything, then unstage the staged skill link. An exclude
|
|
239
|
+
// pathspec on add makes git exit 1 once bootstrap has ignored
|
|
240
|
+
// .claude/skills ("paths are ignored"), which is every hosted session
|
|
241
|
+
// (ORI-2441, git 2.49 in the sandbox). Only the link's own path is reset,
|
|
242
|
+
// so an agent's edits to a team's tracked skills next to it are saved;
|
|
243
|
+
// reset, unlike rm --cached, never deletes a tracked file.
|
|
244
|
+
const add = exec(['add', '-A', '--', '.']);
|
|
239
245
|
if (add.exitCode !== 0) {
|
|
240
246
|
return { kind: 'work_persist_failed', error: `git add failed: ${detail(add)}` };
|
|
241
247
|
}
|
|
248
|
+
const unstage = exec(['reset', '-q', '--', '.claude/skills/orizu']);
|
|
249
|
+
if (unstage.exitCode !== 0) {
|
|
250
|
+
return { kind: 'work_persist_failed', error: `git reset of .claude/skills/orizu failed: ${detail(unstage)}` };
|
|
251
|
+
}
|
|
242
252
|
const commit = exec([
|
|
243
253
|
'-c',
|
|
244
254
|
`user.name=${opts.author.name}`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hosted-session-cli.d.ts","sourceRoot":"","sources":["../src/hosted-session-cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAKH,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACxB,MAAM,uBAAuB,CAAA;AAK9B,OAAO,EAAE,oBAAoB,EAAqB,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"hosted-session-cli.d.ts","sourceRoot":"","sources":["../src/hosted-session-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -46,6 +46,7 @@ import { DEFAULT_HOSTED_MODEL, hostedLoopCommand } from './hosted-loop.js';
|
|
|
46
46
|
import { hostedBootCommand } from './hosted-boot.js';
|
|
47
47
|
import { mergeJobCommand } from './merge-job.js';
|
|
48
48
|
import { workspaceBootstrapJobCommand } from './workspace-bootstrap-job.js';
|
|
49
|
+
import { publishMergeJobCommand } from './publish-merge-job.js';
|
|
49
50
|
import { hostedOptimizationCommand } from './hosted-optimization.js';
|
|
50
51
|
import { writeChildStderr } from './child-output-tee.js';
|
|
51
52
|
import { skilledProposerBakeCommand } from './skilled-proposer-launch.js';
|
|
@@ -1179,6 +1180,10 @@ export async function hostedCommand(args, io, deps = {}) {
|
|
|
1179
1180
|
if (positional[1] === 'workspace-bootstrap-job') {
|
|
1180
1181
|
return workspaceBootstrapJobCommand(args, io);
|
|
1181
1182
|
}
|
|
1183
|
+
// ORI-2280: the one-shot publish merge (coordinator publish-merge job).
|
|
1184
|
+
if (positional[1] === 'publish-merge-job') {
|
|
1185
|
+
return publishMergeJobCommand(args, io);
|
|
1186
|
+
}
|
|
1182
1187
|
if (positional[1] === 'hosted-optimization') {
|
|
1183
1188
|
return hostedOptimizationCommand({ ...io, printErr: writeChildStderr });
|
|
1184
1189
|
}
|
|
@@ -1186,7 +1191,7 @@ export async function hostedCommand(args, io, deps = {}) {
|
|
|
1186
1191
|
return skilledProposerBakeCommand(io);
|
|
1187
1192
|
if (positional[1] === 'verify-skilled-proposer-bake')
|
|
1188
1193
|
return skilledProposerBakeCommand(io, true);
|
|
1189
|
-
io.printErr?.('Usage: orizu internal <hosted-loop --context <path> | hosted-boot | hosted-optimization | merge-job | workspace-bootstrap-job | bake-skilled-proposer-venv | verify-skilled-proposer-bake>');
|
|
1194
|
+
io.printErr?.('Usage: orizu internal <hosted-loop --context <path> | hosted-boot | hosted-optimization | merge-job | workspace-bootstrap-job | publish-merge-job | bake-skilled-proposer-venv | verify-skilled-proposer-bake>');
|
|
1190
1195
|
return 1;
|
|
1191
1196
|
}
|
|
1192
1197
|
const unknownOption = findUnknownOption(args, HOSTED_START_OPTIONS, HOSTED_START_VALUE_OPTIONS);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fills an empty hosted session copy from its team copy (ORI-2118).
|
|
3
|
+
*
|
|
4
|
+
* Artifacts forks of a team copy whose history has a few file-adding commits
|
|
5
|
+
* cannot be cloned or pushed to (measured 2026-10-03, binding and REST). The
|
|
6
|
+
* broker therefore creates the session copy EMPTY, and the sandbox boot fills
|
|
7
|
+
* it here before its first clone: a bare clone of the team copy's `main`, then
|
|
8
|
+
* a push of that `main` into the session copy. A Worker cannot run git, so
|
|
9
|
+
* this is the first place in session start that can.
|
|
10
|
+
*
|
|
11
|
+
* It fills a copy only when the copy has no branches at all, which is what a
|
|
12
|
+
* freshly created copy looks like. A retried or resumed boot finds `main` and
|
|
13
|
+
* does nothing, so it never overwrites the agent's work, and a working
|
|
14
|
+
* repository whose content lives on another branch is never touched. The
|
|
15
|
+
* push is never forced; if another boot filled the copy first, that is fine.
|
|
16
|
+
* Credentials come only through the `-c` settings the caller passes (the
|
|
17
|
+
* boot's credential helper), never in a URL or argument.
|
|
18
|
+
*/
|
|
19
|
+
export declare const SESSION_COPY_SEED_FAILURE = "session copy could not be filled from the team copy";
|
|
20
|
+
interface SeedExecResult {
|
|
21
|
+
status: number;
|
|
22
|
+
stdout: string;
|
|
23
|
+
stderr: string;
|
|
24
|
+
}
|
|
25
|
+
type SeedExec = (cmd: string, args: string[], opts?: {
|
|
26
|
+
cwd?: string;
|
|
27
|
+
}) => SeedExecResult;
|
|
28
|
+
export interface SeedSessionCopyInput {
|
|
29
|
+
exec: SeedExec;
|
|
30
|
+
sessionRemote: string;
|
|
31
|
+
/** `git -c` settings that authenticate to the session copy. */
|
|
32
|
+
sessionGitConfig: string[];
|
|
33
|
+
/** Called only when the copy is empty: the team copy and its `-c` settings. */
|
|
34
|
+
resolveTeam: () => Promise<{
|
|
35
|
+
remote: string;
|
|
36
|
+
gitConfig: string[];
|
|
37
|
+
}>;
|
|
38
|
+
/** A path owned only by this seed operation; cleared before and after use. */
|
|
39
|
+
scratchDir: string;
|
|
40
|
+
}
|
|
41
|
+
export declare function seedSessionCopy(input: SeedSessionCopyInput): Promise<{
|
|
42
|
+
seeded: boolean;
|
|
43
|
+
}>;
|
|
44
|
+
export {};
|
|
45
|
+
//# sourceMappingURL=hosted-session-seed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hosted-session-seed.d.ts","sourceRoot":"","sources":["../src/hosted-session-seed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,eAAO,MAAM,yBAAyB,wDAAwD,CAAA;AAE9F,UAAU,cAAc;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AACD,KAAK,QAAQ,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,cAAc,CAAA;AAExF,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,QAAQ,CAAA;IACd,aAAa,EAAE,MAAM,CAAA;IACrB,+DAA+D;IAC/D,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,+EAA+E;IAC/E,WAAW,EAAE,MAAM,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAA;IACnE,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAA;CACnB;AAoBD,wBAAsB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC,CAoB/F"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fills an empty hosted session copy from its team copy (ORI-2118).
|
|
3
|
+
*
|
|
4
|
+
* Artifacts forks of a team copy whose history has a few file-adding commits
|
|
5
|
+
* cannot be cloned or pushed to (measured 2026-10-03, binding and REST). The
|
|
6
|
+
* broker therefore creates the session copy EMPTY, and the sandbox boot fills
|
|
7
|
+
* it here before its first clone: a bare clone of the team copy's `main`, then
|
|
8
|
+
* a push of that `main` into the session copy. A Worker cannot run git, so
|
|
9
|
+
* this is the first place in session start that can.
|
|
10
|
+
*
|
|
11
|
+
* It fills a copy only when the copy has no branches at all, which is what a
|
|
12
|
+
* freshly created copy looks like. A retried or resumed boot finds `main` and
|
|
13
|
+
* does nothing, so it never overwrites the agent's work, and a working
|
|
14
|
+
* repository whose content lives on another branch is never touched. The
|
|
15
|
+
* push is never forced; if another boot filled the copy first, that is fine.
|
|
16
|
+
* Credentials come only through the `-c` settings the caller passes (the
|
|
17
|
+
* boot's credential helper), never in a URL or argument.
|
|
18
|
+
*/
|
|
19
|
+
export const SESSION_COPY_SEED_FAILURE = 'session copy could not be filled from the team copy';
|
|
20
|
+
function withConfig(config) {
|
|
21
|
+
return config.flatMap(setting => ['-c', setting]);
|
|
22
|
+
}
|
|
23
|
+
function failure(step, result) {
|
|
24
|
+
const detail = (result.stderr || result.stdout || `exit ${result.status}`).trim();
|
|
25
|
+
return new Error(`${SESSION_COPY_SEED_FAILURE}: ${step}: ${detail}`);
|
|
26
|
+
}
|
|
27
|
+
/** Whether the session copy has any branch. Measured on Artifacts: an empty
|
|
28
|
+
* repository answers `ls-remote` with exit 0 and no output. Any non-zero
|
|
29
|
+
* exit is an error, never "empty". */
|
|
30
|
+
function sessionHasBranches(input) {
|
|
31
|
+
const listed = input.exec('git', [...withConfig(input.sessionGitConfig), 'ls-remote', '--heads', input.sessionRemote]);
|
|
32
|
+
if (listed.status !== 0)
|
|
33
|
+
throw failure('reading the session copy', listed);
|
|
34
|
+
return listed.stdout.trim().length > 0;
|
|
35
|
+
}
|
|
36
|
+
export async function seedSessionCopy(input) {
|
|
37
|
+
if (sessionHasBranches(input))
|
|
38
|
+
return { seeded: false };
|
|
39
|
+
const team = await input.resolveTeam();
|
|
40
|
+
try {
|
|
41
|
+
// A sandbox shutdown can interrupt clone before finally runs. This path
|
|
42
|
+
// belongs only to seeding; never clear the surrounding session directory.
|
|
43
|
+
const cleared = input.exec('rm', ['-rf', '--', input.scratchDir]);
|
|
44
|
+
if (cleared.status !== 0)
|
|
45
|
+
throw failure('clearing the seed scratch', cleared);
|
|
46
|
+
const fetched = input.exec('git', [...withConfig(team.gitConfig), 'clone', '--quiet', '--bare', '--single-branch', '--branch', 'main', team.remote, input.scratchDir]);
|
|
47
|
+
if (fetched.status !== 0)
|
|
48
|
+
throw failure('reading the team copy', fetched);
|
|
49
|
+
const pushed = input.exec('git', ['-C', input.scratchDir, ...withConfig(input.sessionGitConfig), 'push', '--quiet', input.sessionRemote, 'refs/heads/main:refs/heads/main']);
|
|
50
|
+
if (pushed.status !== 0) {
|
|
51
|
+
// Another boot of the same session may have filled it first.
|
|
52
|
+
if (sessionHasBranches(input))
|
|
53
|
+
return { seeded: false };
|
|
54
|
+
throw failure('pushing into the session copy', pushed);
|
|
55
|
+
}
|
|
56
|
+
return { seeded: true };
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
input.exec('rm', ['-rf', '--', input.scratchDir]);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -15,7 +15,11 @@
|
|
|
15
15
|
* skill-installer; the local-sim rehearsal sets it),
|
|
16
16
|
* (2) `orizu skills path` — the packaged vendor/skills/orizu of the
|
|
17
17
|
* globally-installed CLI (the production path),
|
|
18
|
-
* (3)
|
|
18
|
+
* (3) `/opt/orizu/cli/vendor/skills/orizu` — the canonical copy the
|
|
19
|
+
* published-package bake installs (ORI-2375: in a prebaked sandbox the
|
|
20
|
+
* sandbox user's npm prefix never holds the sudo-installed package),
|
|
21
|
+
* (4) `$(npm root -g)/orizu/vendor/skills/orizu` — for the non-prebaked
|
|
22
|
+
* bootstrap, which installs orizu globally and has no /opt/orizu/cli.
|
|
19
23
|
* Then SYMLINK it under `<workspaceDir>/.claude/skills/orizu`, falling back to
|
|
20
24
|
* a copy if the symlink cannot be created. Resolved paths stay in shell vars
|
|
21
25
|
* (never interpolated), so they cannot inject into the command.
|
|
@@ -55,8 +59,9 @@ export interface StageOrizuSkillResult {
|
|
|
55
59
|
stdout: string;
|
|
56
60
|
stderr: string;
|
|
57
61
|
}
|
|
58
|
-
/** The exact staging script — exported for tests that assert its shape
|
|
59
|
-
|
|
62
|
+
/** The exact staging script — exported for tests that assert its shape and run it
|
|
63
|
+
* (`canonicalSkillDir` lets a test lay the canonical copy out under a temp root). */
|
|
64
|
+
export declare function renderStageOrizuSkillScript(workspaceDir: string, canonicalSkillDir?: string): string;
|
|
60
65
|
/**
|
|
61
66
|
* Stage the orizu skill into `<workspaceDir>/.claude/skills/orizu`.
|
|
62
67
|
* Non-throwing (except via the injected exec): resolves to a structured result
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hosted-skill-staging.d.ts","sourceRoot":"","sources":["../src/hosted-skill-staging.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"hosted-skill-staging.d.ts","sourceRoot":"","sources":["../src/hosted-skill-staging.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAA;AAE/E,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,cAAc,CAAA;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,OAAO,CAAA;IACX,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,WAAW,GAAG,IAAI,CAAA;IAC/C,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAYD;sFACsF;AACtF,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,EAAE,iBAAiB,SAAsB,GAAG,MAAM,CAqBjH;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAuBlG"}
|
|
@@ -15,7 +15,11 @@
|
|
|
15
15
|
* skill-installer; the local-sim rehearsal sets it),
|
|
16
16
|
* (2) `orizu skills path` — the packaged vendor/skills/orizu of the
|
|
17
17
|
* globally-installed CLI (the production path),
|
|
18
|
-
* (3)
|
|
18
|
+
* (3) `/opt/orizu/cli/vendor/skills/orizu` — the canonical copy the
|
|
19
|
+
* published-package bake installs (ORI-2375: in a prebaked sandbox the
|
|
20
|
+
* sandbox user's npm prefix never holds the sudo-installed package),
|
|
21
|
+
* (4) `$(npm root -g)/orizu/vendor/skills/orizu` — for the non-prebaked
|
|
22
|
+
* bootstrap, which installs orizu globally and has no /opt/orizu/cli.
|
|
19
23
|
* Then SYMLINK it under `<workspaceDir>/.claude/skills/orizu`, falling back to
|
|
20
24
|
* a copy if the symlink cannot be created. Resolved paths stay in shell vars
|
|
21
25
|
* (never interpolated), so they cannot inject into the command.
|
|
@@ -32,8 +36,10 @@
|
|
|
32
36
|
// non-traversal directory (both do: `<root>/repo` on the DO path, `repo` on the
|
|
33
37
|
// operator path) — never an untrusted or user-supplied value.
|
|
34
38
|
const SAFE_WORKSPACE_DIR = /^[A-Za-z0-9._/:@-]+$/;
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
const CANONICAL_SKILL_DIR = '/opt/orizu/cli/vendor/skills/orizu';
|
|
40
|
+
/** The exact staging script — exported for tests that assert its shape and run it
|
|
41
|
+
* (`canonicalSkillDir` lets a test lay the canonical copy out under a temp root). */
|
|
42
|
+
export function renderStageOrizuSkillScript(workspaceDir, canonicalSkillDir = CANONICAL_SKILL_DIR) {
|
|
37
43
|
const skillsDir = `${workspaceDir}/.claude/skills`;
|
|
38
44
|
return [
|
|
39
45
|
`mkdir -p ${skillsDir}`,
|
|
@@ -48,6 +54,7 @@ export function renderStageOrizuSkillScript(workspaceDir) {
|
|
|
48
54
|
`if [ -d ${workspaceDir}/.git ] && git -C ${workspaceDir} ls-files -- '.claude/skills/orizu' '.claude/skills/orizu/**' | grep -q .; then if [ -f "$dest/SKILL.md" ]; then echo "PRESERVED_TRACKED $dest"; else echo "PRESERVED_INVALID $dest"; fi; exit 0; fi`,
|
|
49
55
|
`src="${'${ORIZU_SKILL_SOURCE_DIR:-}'}"`,
|
|
50
56
|
`if [ -z "$src" ] || [ ! -d "$src" ]; then src="$(orizu skills path 2>/dev/null || true)"; fi`,
|
|
57
|
+
`if [ -z "$src" ] || [ ! -d "$src" ]; then src='${canonicalSkillDir}'; fi`,
|
|
51
58
|
`if [ -z "$src" ] || [ ! -d "$src" ]; then r="$(npm root -g 2>/dev/null || true)"; if [ -n "$r" ] && [ -d "$r/orizu/vendor/skills/orizu" ]; then src="$r/orizu/vendor/skills/orizu"; fi; fi`,
|
|
52
59
|
`if [ -z "$src" ] || [ ! -d "$src" ]; then echo "NO_SOURCE"; exit 0; fi`,
|
|
53
60
|
`rm -rf "$dest"`,
|
package/dist/jsonl-stream.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export declare const JSONL_UPLOAD_CHUNK_MAX_BYTES: number;
|
|
2
2
|
interface JsonlChunkOptions {
|
|
3
3
|
maxPayloadBytes?: number;
|
|
4
|
+
signal?: AbortSignal;
|
|
4
5
|
}
|
|
5
6
|
export declare function estimateRowsPayloadByteLength(rows: Array<Record<string, unknown>>): number;
|
|
6
7
|
export declare function streamJsonlRowChunks(filePath: string, options?: JsonlChunkOptions): AsyncGenerator<Array<Record<string, unknown>>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonl-stream.d.ts","sourceRoot":"","sources":["../src/jsonl-stream.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,4BAA4B,QAAkB,CAAA;AAE3D,UAAU,iBAAiB;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"jsonl-stream.d.ts","sourceRoot":"","sources":["../src/jsonl-stream.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,4BAA4B,QAAkB,CAAA;AAE3D,UAAU,iBAAiB;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AA2CD,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,CAM1F;AAED,wBAAuB,oBAAoB,CACzC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,iBAAsB,GAC9B,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CA4EhD"}
|
package/dist/jsonl-stream.js
CHANGED
|
@@ -37,11 +37,17 @@ export async function* streamJsonlRowChunks(filePath, options = {}) {
|
|
|
37
37
|
let chunkRowsByteLength = 0;
|
|
38
38
|
let parsedRowCount = 0;
|
|
39
39
|
let lineNumber = 0;
|
|
40
|
+
if (options.signal?.aborted)
|
|
41
|
+
throw new Error('Dataset input interrupted');
|
|
40
42
|
const stream = createReadStream(filePath, { encoding: 'utf8' });
|
|
41
43
|
const lines = createInterface({
|
|
42
44
|
input: stream,
|
|
43
45
|
crlfDelay: Infinity,
|
|
44
46
|
});
|
|
47
|
+
// Closing the owned reader unblocks an outstanding next() before a scoped
|
|
48
|
+
// caller awaits return(); return alone would queue behind that pending read.
|
|
49
|
+
const interrupt = () => { lines.close(); stream.destroy(); };
|
|
50
|
+
options.signal?.addEventListener('abort', interrupt, { once: true });
|
|
45
51
|
try {
|
|
46
52
|
for await (const line of lines) {
|
|
47
53
|
lineNumber += 1;
|
|
@@ -79,6 +85,7 @@ export async function* streamJsonlRowChunks(filePath, options = {}) {
|
|
|
79
85
|
throw mapReadError(filePath, error);
|
|
80
86
|
}
|
|
81
87
|
finally {
|
|
88
|
+
options.signal?.removeEventListener('abort', interrupt);
|
|
82
89
|
lines.close();
|
|
83
90
|
stream.destroy();
|
|
84
91
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-list-workflow.d.ts","sourceRoot":"","sources":["../src/provider-list-workflow.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAoDnE,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiDzG"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Context, Effect, Result, Schema } from 'effect';
|
|
2
|
+
import { authedFetch } from './http.js';
|
|
3
|
+
import { providerWireRecord as record } from './provider-wire-record.js';
|
|
4
|
+
import { isProviderRefusalCode } from './provider-refusals.js';
|
|
5
|
+
function providerListFailureMessage(failure) {
|
|
6
|
+
switch (failure._tag) {
|
|
7
|
+
case 'Http': return failure.message;
|
|
8
|
+
case 'Transport': return 'Provider request failed';
|
|
9
|
+
// Project selection remains the existing, separately owned adapter.
|
|
10
|
+
case 'Resolution':
|
|
11
|
+
case 'Adapter': return failure.message;
|
|
12
|
+
default: {
|
|
13
|
+
const exhaustive = failure;
|
|
14
|
+
return exhaustive;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const ProviderListTransport = Context.Service('orizu/cli/ProviderListTransport');
|
|
19
|
+
const WireRecord = Schema.Record(Schema.String, Schema.Unknown);
|
|
20
|
+
const emptyWireRecord = {};
|
|
21
|
+
function providerListProgram(project, io) {
|
|
22
|
+
return Effect.gen(function* () {
|
|
23
|
+
const transport = yield* ProviderListTransport;
|
|
24
|
+
const response = yield* transport.read(project);
|
|
25
|
+
// Decode raw wire data; malformed JSON and non-record bodies retain the
|
|
26
|
+
// existing empty record fallback without narrowing accepted record fields.
|
|
27
|
+
const value = yield* Effect.promise(() => response.json().catch(() => null));
|
|
28
|
+
const body = yield* Schema.decodeUnknownEffect(WireRecord)(value).pipe(Effect.catch(() => Effect.succeed(emptyWireRecord)));
|
|
29
|
+
if (!response.ok) {
|
|
30
|
+
const message = typeof body.error === 'string' && isProviderRefusalCode(body.error) ? body.error : 'Provider request failed';
|
|
31
|
+
return yield* Effect.fail({ _tag: 'Http', message });
|
|
32
|
+
}
|
|
33
|
+
yield* Effect.sync(() => {
|
|
34
|
+
if (io.json)
|
|
35
|
+
io.print(JSON.stringify(body));
|
|
36
|
+
else {
|
|
37
|
+
io.print('ID PROTOCOL HOST CREDENTIAL ENV BUILT-IN');
|
|
38
|
+
for (const value of Array.isArray(body.providers) ? body.providers : []) {
|
|
39
|
+
const row = record(value);
|
|
40
|
+
io.print(`${row.id} ${row.protocol} ${row.host} ${row.credentialEnv} ${row.builtIn ? 'yes' : 'no'}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
export async function listProviders(projectArg, io) {
|
|
47
|
+
const controller = new AbortController();
|
|
48
|
+
let interrupted;
|
|
49
|
+
const interrupt = () => { interrupted = 130; controller.abort(); };
|
|
50
|
+
const terminate = () => { interrupted = 143; controller.abort(); };
|
|
51
|
+
const transport = {
|
|
52
|
+
read: (project) => Effect.tryPromise({
|
|
53
|
+
try: signal => (io.fetcher ?? authedFetch)(`/api/cli/providers?project=${encodeURIComponent(project)}`, {
|
|
54
|
+
method: 'GET', signal: AbortSignal.any([signal, controller.signal]),
|
|
55
|
+
}),
|
|
56
|
+
// The retained HTTP adapter exposes login/config/refresh diagnostics as
|
|
57
|
+
// untyped Error values. Preserve its public messages until ORI-2420
|
|
58
|
+
// supplies typed adapter failures; never expose nested transport causes.
|
|
59
|
+
catch: (cause) => cause instanceof Error
|
|
60
|
+
? { _tag: 'Adapter', message: cause.message }
|
|
61
|
+
: { _tag: 'Transport' },
|
|
62
|
+
}),
|
|
63
|
+
};
|
|
64
|
+
const program = Effect.gen(function* () {
|
|
65
|
+
const project = yield* Effect.tryPromise({
|
|
66
|
+
try: async () => {
|
|
67
|
+
const project = await io.resolveProjectSlug?.(projectArg);
|
|
68
|
+
if (!project)
|
|
69
|
+
throw new Error('Project resolver unavailable');
|
|
70
|
+
return project;
|
|
71
|
+
},
|
|
72
|
+
catch: (cause) => ({ _tag: 'Resolution', message: cause instanceof Error ? cause.message : 'Provider request failed' }),
|
|
73
|
+
});
|
|
74
|
+
// The retained resolver is unsignalled. Do not suppress Node's natural
|
|
75
|
+
// termination until the cancellable catalog transport has been admitted.
|
|
76
|
+
return yield* Effect.acquireUseRelease(Effect.sync(() => { process.once('SIGINT', interrupt); process.once('SIGTERM', terminate); }), () => providerListProgram(project, io).pipe(Effect.provideService(ProviderListTransport, transport)), () => Effect.sync(() => {
|
|
77
|
+
process.removeListener('SIGINT', interrupt);
|
|
78
|
+
process.removeListener('SIGTERM', terminate);
|
|
79
|
+
}));
|
|
80
|
+
});
|
|
81
|
+
try {
|
|
82
|
+
const result = await Effect.runPromise(Effect.result(program), { signal: controller.signal });
|
|
83
|
+
if (Result.isSuccess(result))
|
|
84
|
+
return 0;
|
|
85
|
+
const message = providerListFailureMessage(result.failure);
|
|
86
|
+
io.print(io.json ? JSON.stringify({ error: message }) : message);
|
|
87
|
+
return 1;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
if (interrupted !== undefined)
|
|
91
|
+
return interrupted;
|
|
92
|
+
io.print(io.json ? JSON.stringify({ error: 'Provider request failed' }) : 'Provider request failed');
|
|
93
|
+
return 1;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-wire-record.d.ts","sourceRoot":"","sources":["../src/provider-wire-record.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAE1E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"providers-cli.d.ts","sourceRoot":"","sources":["../src/providers-cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"providers-cli.d.ts","sourceRoot":"","sources":["../src/providers-cli.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAsEnE,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,qBAAqB,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAmEzH"}
|
package/dist/providers-cli.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { authedFetch } from './http.js';
|
|
2
|
+
import { providerWireRecord as object } from './provider-wire-record.js';
|
|
2
3
|
import { credentialEnvFor, providerLookupFor } from './provider-lookup.js';
|
|
3
4
|
import { CREDENTIAL_ENV_PATTERN, PROVIDER_FIELD_PATTERNS, RESERVED_CREDENTIAL_ENVS, isProviderRefusalCode } from './provider-refusals.js';
|
|
4
5
|
import { findProvider, parseModelIdentity } from './provider-registry.js';
|
|
5
6
|
import { PROBE_PROTOCOLS, probeProvider, probeTarget } from './provider-probe.js';
|
|
6
7
|
const FIELD_CONTRACT = 'Anthropic Messages base URL excludes /v1; OpenAI base URLs include the version segment.';
|
|
7
|
-
function object(value) {
|
|
8
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value) ? Object.fromEntries(Object.entries(value)) : {};
|
|
9
|
-
}
|
|
10
8
|
function assertProtocol(value) {
|
|
11
9
|
if (typeof value !== 'string' || !Object.hasOwn(PROBE_PROTOCOLS, value))
|
|
12
10
|
throw new Error('provider_protocol_invalid');
|
|
@@ -99,6 +97,10 @@ export async function providersCommand(args, io, checkIdentity) {
|
|
|
99
97
|
baseUrl = baseUrl.replace(/^(https:\/\/)([^/]+)/, (_, scheme, host) => scheme + host.toLowerCase());
|
|
100
98
|
provider = providerRow({ id, baseUrl, protocol: flags.get('--protocol') ?? 'openai-chat', credentialEnv: flags.get('--credential-env') ?? credentialEnvFor(id), authHeader: flags.get('--auth-header') ?? 'Authorization', authValuePrefix: flags.get('--auth-value-prefix') ?? 'Bearer ' });
|
|
101
99
|
}
|
|
100
|
+
if (checkIdentity === undefined && command === 'list' && positional.length === 1) {
|
|
101
|
+
const { listProviders } = await import('./provider-list-workflow.js');
|
|
102
|
+
return listProviders(flags.get('--project') || null, io);
|
|
103
|
+
}
|
|
102
104
|
const project = await io.resolveProjectSlug?.(flags.get('--project') || null);
|
|
103
105
|
if (!project)
|
|
104
106
|
throw new Error('Project resolver unavailable');
|
|
@@ -131,18 +133,6 @@ export async function providersCommand(args, io, checkIdentity) {
|
|
|
131
133
|
throw new Error('provider_not_found');
|
|
132
134
|
await runProbe(entry, identity.modelId, io);
|
|
133
135
|
}
|
|
134
|
-
else if (command === 'list' && positional.length === 1) {
|
|
135
|
-
const body = await request(root, { method: 'GET' });
|
|
136
|
-
if (io.json)
|
|
137
|
-
io.print(JSON.stringify(body));
|
|
138
|
-
else {
|
|
139
|
-
io.print('ID PROTOCOL HOST CREDENTIAL ENV BUILT-IN');
|
|
140
|
-
for (const value of Array.isArray(body.providers) ? body.providers : []) {
|
|
141
|
-
const row = object(value);
|
|
142
|
-
io.print(`${row.id} ${row.protocol} ${row.host} ${row.credentialEnv} ${row.builtIn ? 'yes' : 'no'}`);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
136
|
else if (command === 'remove' && id && positional.length === 2) {
|
|
147
137
|
await request(`/api/cli/providers/${encodeURIComponent(id)}?project=${encodeURIComponent(project)}`, { method: 'DELETE' });
|
|
148
138
|
io.print(io.json ? JSON.stringify({ removed: id }) : `Removed provider ${id}`);
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { type PublishMergeJobFailureCode } from './publish-merge-timing.js';
|
|
2
|
+
/** ADR-012's envelope for a repository's whole object graph. The graph is
|
|
3
|
+
* always larger than the content it was seeded from, so ADR-011's 1 GiB
|
|
4
|
+
* content limit is not the measure here. */
|
|
5
|
+
declare const ADMISSION: {
|
|
6
|
+
totalBytes: number;
|
|
7
|
+
objectBytes: number;
|
|
8
|
+
objects: number;
|
|
9
|
+
commits: number;
|
|
10
|
+
};
|
|
11
|
+
interface PublishMergeJobEnv {
|
|
12
|
+
bootSecret: string;
|
|
13
|
+
jobId: string;
|
|
14
|
+
coordinatorUrl: string;
|
|
15
|
+
baseUrl: string;
|
|
16
|
+
/** The Artifacts git host the coordinator expects; localhost only in tests. */
|
|
17
|
+
expectedGitHost: string;
|
|
18
|
+
/** The coordinator's wall, epoch ms; see the timing note above. */
|
|
19
|
+
wallAt?: number;
|
|
20
|
+
}
|
|
21
|
+
export type PublishMergeJobOutcome = {
|
|
22
|
+
outcome: 'merged';
|
|
23
|
+
mergeSha: string;
|
|
24
|
+
} | {
|
|
25
|
+
outcome: 'already_merged';
|
|
26
|
+
headSha: string;
|
|
27
|
+
}
|
|
28
|
+
/** At most PUBLISH_MERGE_CONFLICT_FILES_LIMIT paths; `moreFiles` counts the rest. */
|
|
29
|
+
| {
|
|
30
|
+
outcome: 'conflict';
|
|
31
|
+
files: readonly string[];
|
|
32
|
+
moreFiles: number;
|
|
33
|
+
} | {
|
|
34
|
+
outcome: 'denied';
|
|
35
|
+
} | {
|
|
36
|
+
outcome: 'race_lost';
|
|
37
|
+
} | {
|
|
38
|
+
outcome: 'failed';
|
|
39
|
+
code: PublishMergeJobFailureCode;
|
|
40
|
+
};
|
|
41
|
+
/** One `<type> <size>` line per object, as `git cat-file --batch-check` prints them. */
|
|
42
|
+
export declare function isMergeInventoryAdmitted(inventory: string, narrower?: Partial<typeof ADMISSION>): boolean;
|
|
43
|
+
/** The conflict list the job reports, bounded so the result always fits the
|
|
44
|
+
* coordinator's body limit. A path too long to name is counted instead. */
|
|
45
|
+
export declare function boundConflictFiles(files: readonly string[]): {
|
|
46
|
+
files: string[];
|
|
47
|
+
moreFiles: number;
|
|
48
|
+
};
|
|
49
|
+
export declare function runPublishMergeJob(options: {
|
|
50
|
+
env: PublishMergeJobEnv;
|
|
51
|
+
deadlineMs?: number;
|
|
52
|
+
/** Narrower admission limits; tests only. Never wider than ADMISSION. */
|
|
53
|
+
admission?: Partial<typeof ADMISSION>;
|
|
54
|
+
/** Shorter timing; tests only. Each is clamped to its production value. */
|
|
55
|
+
timing?: {
|
|
56
|
+
resultReserveMs?: number;
|
|
57
|
+
lateCallMs?: number;
|
|
58
|
+
};
|
|
59
|
+
}): Promise<{
|
|
60
|
+
reported: boolean;
|
|
61
|
+
outcome: PublishMergeJobOutcome;
|
|
62
|
+
}>;
|
|
63
|
+
export declare function publishMergeJobCommand(args: readonly string[], io: {
|
|
64
|
+
print: (line: string) => void;
|
|
65
|
+
printErr?: (line: string) => void;
|
|
66
|
+
}): Promise<number>;
|
|
67
|
+
export {};
|
|
68
|
+
//# sourceMappingURL=publish-merge-job.d.ts.map
|