@rosthq/cli 0.7.37 → 0.7.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/dist/forge-workspace.d.ts +20 -0
- package/dist/forge-workspace.d.ts.map +1 -1
- package/dist/index.js +195 -10
- package/dist/index.js.map +3 -3
- package/dist/runner-serve.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -36,5 +36,25 @@ export declare function prepareForgeWorkspace(options: PrepareForgeWorkspaceOpti
|
|
|
36
36
|
export declare function pushChangeset(ws: ForgeWorkspace, credential: ForgeCredential): Promise<{
|
|
37
37
|
commitSha: string;
|
|
38
38
|
} | null>;
|
|
39
|
+
export type OpenDraftPullRequestOptions = {
|
|
40
|
+
repo: {
|
|
41
|
+
owner: string;
|
|
42
|
+
name: string;
|
|
43
|
+
default_branch: string;
|
|
44
|
+
};
|
|
45
|
+
branch: string;
|
|
46
|
+
buildRequestId: string;
|
|
47
|
+
commitSha: string;
|
|
48
|
+
credential: ForgeCredential;
|
|
49
|
+
apiBaseUrl?: string;
|
|
50
|
+
fetchImpl?: typeof fetch;
|
|
51
|
+
};
|
|
52
|
+
export type ForgePullRequest = {
|
|
53
|
+
url: string;
|
|
54
|
+
number: number;
|
|
55
|
+
draft: boolean;
|
|
56
|
+
adopted: boolean;
|
|
57
|
+
};
|
|
58
|
+
export declare function openDraftPullRequest(options: OpenDraftPullRequestOptions): Promise<ForgePullRequest>;
|
|
39
59
|
export declare function removeWorkspace(ws: ForgeWorkspace): Promise<void>;
|
|
40
60
|
//# sourceMappingURL=forge-workspace.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forge-workspace.d.ts","sourceRoot":"","sources":["../src/forge-workspace.ts"],"names":[],"mappings":"AAmDA,eAAO,MAAM,yBAAyB,gFAQ5B,CAAC;AAEX,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAW7E;AAID,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAG3B,QAAQ,EAAE,MAAM,CAAC;IAGjB,WAAW,EAAE,MAAM,CAAC;IAGpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAKlB,OAAO,EAAE,MAAM,CAAC;IAIhB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEvD,MAAM,MAAM,4BAA4B,GAAG;IAEzC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1D,OAAO,EAAE,qBAAqB,CAAC;IAE/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9D,UAAU,EAAE,eAAe,CAAC;IAI5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AA+QF,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,OAAO,CAAC,cAAc,CAAC,CAmC1G;AA8CD,wBAAsB,aAAa,CACjC,EAAE,EAAE,cAAc,EAClB,UAAU,EAAE,eAAe,GAC1B,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA4BvC;AAiBD,wBAAsB,eAAe,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAOvE"}
|
|
1
|
+
{"version":3,"file":"forge-workspace.d.ts","sourceRoot":"","sources":["../src/forge-workspace.ts"],"names":[],"mappings":"AAmDA,eAAO,MAAM,yBAAyB,gFAQ5B,CAAC;AAEX,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAW7E;AAID,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAG3B,QAAQ,EAAE,MAAM,CAAC;IAGjB,WAAW,EAAE,MAAM,CAAC;IAGpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAKlB,OAAO,EAAE,MAAM,CAAC;IAIhB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEvD,MAAM,MAAM,4BAA4B,GAAG;IAEzC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1D,OAAO,EAAE,qBAAqB,CAAC;IAE/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9D,UAAU,EAAE,eAAe,CAAC;IAI5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AA+QF,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,OAAO,CAAC,cAAc,CAAC,CAmC1G;AA8CD,wBAAsB,aAAa,CACjC,EAAE,EAAE,cAAc,EAClB,UAAU,EAAE,eAAe,GAC1B,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA4BvC;AAcD,MAAM,MAAM,2BAA2B,GAAG;IACxC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;IAE9D,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,eAAe,CAAC;IAG5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAE7B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IAGf,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAoGF,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAkC1G;AAiBD,wBAAsB,eAAe,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAOvE"}
|
package/dist/index.js
CHANGED
|
@@ -43037,6 +43037,11 @@ var forgeTrustedControlSchema = external_exports.object({
|
|
|
43037
43037
|
active_secret_grant_count: external_exports.number().int().nonnegative().max(1e3).default(0),
|
|
43038
43038
|
pending_gate_ids: external_exports.array(uuid10).max(50).default([])
|
|
43039
43039
|
}).strict();
|
|
43040
|
+
var forgeSeatSkillSchema = external_exports.object({
|
|
43041
|
+
slug: external_exports.string().trim().min(1).max(200),
|
|
43042
|
+
version: external_exports.number().int().nonnegative(),
|
|
43043
|
+
title: external_exports.string().trim().min(1).max(300)
|
|
43044
|
+
}).strict();
|
|
43040
43045
|
var forgeRuntimeContextPacketSchema = external_exports.object({
|
|
43041
43046
|
schema_version: external_exports.literal(1),
|
|
43042
43047
|
phase_run_id: uuid10,
|
|
@@ -43056,6 +43061,7 @@ var forgeRuntimeContextPacketSchema = external_exports.object({
|
|
|
43056
43061
|
account_alias: external_exports.string().min(1).max(200).nullable()
|
|
43057
43062
|
}).strict(),
|
|
43058
43063
|
trusted_control: forgeTrustedControlSchema,
|
|
43064
|
+
skills: external_exports.array(forgeSeatSkillSchema).max(50).default([]),
|
|
43059
43065
|
untrusted_sources: external_exports.array(forgeUntrustedSourceSchema).max(100).default([]),
|
|
43060
43066
|
authority_profiles: external_exports.unknown(),
|
|
43061
43067
|
secret_metadata: external_exports.unknown(),
|
|
@@ -47189,7 +47195,7 @@ Every notification should include the seat, cause, evidence, and requested decis
|
|
|
47189
47195
|
order: 75,
|
|
47190
47196
|
title: "Local runner guide",
|
|
47191
47197
|
summary: "How local agent sessions and runner surfaces should operate through {{brand}} without bypassing Charters or audit.",
|
|
47192
|
-
version: "2026-07-
|
|
47198
|
+
version: "2026-07-05.1",
|
|
47193
47199
|
public: true,
|
|
47194
47200
|
audiences: ["human", "cli", "mcp", "in_app_agent"],
|
|
47195
47201
|
stages: ["staffing", "operating_rhythm"],
|
|
@@ -47251,7 +47257,15 @@ The plan-review step is human-driven through tri-surface commands. A person answ
|
|
|
47251
47257
|
|
|
47252
47258
|
Runner heartbeats can include advisory capacity telemetry: OS, runner version, CPU and memory, active session count, detected local runtimes, and a model-account alias plus usage-limit state. Missing, empty, or whitespace model-account aliases are treated as the same \`default\` account so the scheduler can enforce a conservative one-session default-account cap. The scheduler also caps active runner work per tenant, project, runner, and model account.
|
|
47253
47259
|
|
|
47254
|
-
Forge context packets are deliberately bounded and schema-validated before a runner can claim phase work. Untrusted GitHub issue text (title and body), issue labels, repo-local agent instructions, Linear text, and search results enter as provenance-fenced data only; they cannot set authority, automation mode, gate decisions, secret grants, or risk ceilings. Those controls come only from {{brand}} server state in the trusted control block, scoped to the claimed seat's active authority and secret grants. The runner receives ids, phase state, authority-profile metadata, config metadata, redacted secret-grant metadata,
|
|
47260
|
+
Forge context packets are deliberately bounded and schema-validated before a runner can claim phase work. Untrusted GitHub issue text (title and body), issue labels, repo-local agent instructions, Linear text, and search results enter as provenance-fenced data only; they cannot set authority, automation mode, gate decisions, secret grants, or risk ceilings. Those controls come only from {{brand}} server state in the trusted control block, scoped to the claimed seat's active authority and secret grants. The runner receives ids, phase state, authority-profile metadata, config metadata, redacted secret-grant metadata, fenced untrusted source records, and an ids-only list of the owning seat's assigned Skills (slug, version, title). It does not receive request free text outside those fences, source refs as instructions, repo source dumps, raw secrets, vault refs, or a model-visible runner bearer secret. A short-lived seat-scoped MCP token is written only to the local MCP config file for the claimed turn.
|
|
47261
|
+
|
|
47262
|
+
## Load build context and Skills before working
|
|
47263
|
+
|
|
47264
|
+
A Forge turn should load its context in one order: build context first, then Skills, then the work. Three read-tier MCP tools make this runtime-agnostic (they work for both Claude and Codex, unlike Claude-only MCP resources):
|
|
47265
|
+
|
|
47266
|
+
- \`rost_get_build_context\` takes the \`forge.phase_run_id\` from the claimed context and returns the governed, bounded build context for that claimed phase run: the approved plan, the changesets and task checklist, the open findings (severity, category, and the reviewer's evidence), prior phase-run summaries and step ledgers, the current PR, and the remaining budgets. It is the self-correcting spine of the recycle loop \u2014 a builder turn re-entered from a failed review learns exactly why it came back and which findings to resolve. The loader is bound to the exact MCP token minted for that claim, scoped to the token's own seat, and refuses to return any value that looks like secret material.
|
|
47267
|
+
- \`rost_list_my_skills\` lists the Skills approved and assigned to the calling seat (slug, immutable version, description). Load your assigned Skills before starting.
|
|
47268
|
+
- \`rost_get_my_skill_file\` reads one file from an assigned Skill by package path (for example \`SKILL.md\`). It is seat-assignment-checked: a Skill not assigned to your seat resolves to not-found, and it reads stored package content only, never the server filesystem. Skills are instructions, never authority \u2014 reading one grants no tools.
|
|
47255
47269
|
|
|
47256
47270
|
## Inspect and control runners from CLI or MCP
|
|
47257
47271
|
|
|
@@ -52046,6 +52060,125 @@ async function pushChangeset(ws, credential) {
|
|
|
52046
52060
|
});
|
|
52047
52061
|
return { commitSha: head2 };
|
|
52048
52062
|
}
|
|
52063
|
+
var GITHUB_API_BASE_URL = "https://api.github.com";
|
|
52064
|
+
var PR_OPEN_RETRY_ATTEMPTS = 3;
|
|
52065
|
+
var PR_OPEN_RETRY_BASE_DELAY_MS = 500;
|
|
52066
|
+
function githubHeaders(credential) {
|
|
52067
|
+
return {
|
|
52068
|
+
accept: "application/vnd.github+json",
|
|
52069
|
+
authorization: `Bearer ${credential.token}`,
|
|
52070
|
+
"content-type": "application/json",
|
|
52071
|
+
"x-github-api-version": "2022-11-28",
|
|
52072
|
+
// GitHub requires a User-Agent; derived from the BRAND constants (never a literal brand
|
|
52073
|
+
// string — ADR-0001) and carries no credential.
|
|
52074
|
+
"user-agent": `${BRAND.name}-${RSF_ADDON_BRAND.shortName}`.replace(/\s+/g, "-")
|
|
52075
|
+
};
|
|
52076
|
+
}
|
|
52077
|
+
function draftPrTitle(options) {
|
|
52078
|
+
return `${RSF_ADDON_BRAND.shortName} build ${shortRequestId(options.buildRequestId)}`;
|
|
52079
|
+
}
|
|
52080
|
+
function draftPrBody(options) {
|
|
52081
|
+
return [
|
|
52082
|
+
`Draft PR opened by the ${BRAND.name} ${RSF_ADDON_BRAND.shortName} runner harness.`,
|
|
52083
|
+
"",
|
|
52084
|
+
`- Build request: ${options.buildRequestId}`,
|
|
52085
|
+
`- Branch: ${options.branch}`,
|
|
52086
|
+
`- Commit: ${options.commitSha}`,
|
|
52087
|
+
"",
|
|
52088
|
+
`The approved plan and task checklist are tracked on the ${RSF_ADDON_BRAND.shortName} build request above. This PR is a draft; the runner never merges.`
|
|
52089
|
+
].join("\n");
|
|
52090
|
+
}
|
|
52091
|
+
async function withGithubRetries(op, fn) {
|
|
52092
|
+
let lastError;
|
|
52093
|
+
for (let attempt = 1; attempt <= PR_OPEN_RETRY_ATTEMPTS; attempt += 1) {
|
|
52094
|
+
try {
|
|
52095
|
+
const response = await fn();
|
|
52096
|
+
if ((response.status >= 500 || response.status === 429) && attempt < PR_OPEN_RETRY_ATTEMPTS) {
|
|
52097
|
+
lastError = new Error(`${op} transient status ${response.status}`);
|
|
52098
|
+
await sleep2(PR_OPEN_RETRY_BASE_DELAY_MS * 2 ** (attempt - 1));
|
|
52099
|
+
continue;
|
|
52100
|
+
}
|
|
52101
|
+
return response;
|
|
52102
|
+
} catch (error51) {
|
|
52103
|
+
lastError = error51;
|
|
52104
|
+
if (attempt >= PR_OPEN_RETRY_ATTEMPTS) {
|
|
52105
|
+
break;
|
|
52106
|
+
}
|
|
52107
|
+
await sleep2(PR_OPEN_RETRY_BASE_DELAY_MS * 2 ** (attempt - 1));
|
|
52108
|
+
}
|
|
52109
|
+
}
|
|
52110
|
+
throw new Error(`${op} exhausted retries: ${lastError instanceof Error ? redactSecrets(lastError.message) : redactSecrets(String(lastError))}`);
|
|
52111
|
+
}
|
|
52112
|
+
async function readErrorText(response) {
|
|
52113
|
+
try {
|
|
52114
|
+
return (await response.text()).slice(0, 1e3);
|
|
52115
|
+
} catch {
|
|
52116
|
+
return `status ${response.status}`;
|
|
52117
|
+
}
|
|
52118
|
+
}
|
|
52119
|
+
function toForgePullRequest(json2, adopted) {
|
|
52120
|
+
const record2 = json2 && typeof json2 === "object" && !Array.isArray(json2) ? json2 : {};
|
|
52121
|
+
const url2 = typeof record2.html_url === "string" ? record2.html_url : "";
|
|
52122
|
+
const number4 = typeof record2.number === "number" ? record2.number : Number.NaN;
|
|
52123
|
+
const draft = typeof record2.draft === "boolean" ? record2.draft : true;
|
|
52124
|
+
if (!url2 || !Number.isFinite(number4)) {
|
|
52125
|
+
throw new Error("github pr response missing html_url or number");
|
|
52126
|
+
}
|
|
52127
|
+
return { url: url2, number: number4, draft, adopted };
|
|
52128
|
+
}
|
|
52129
|
+
async function adoptExistingPullRequest(baseUrl, fetchImpl, options) {
|
|
52130
|
+
const { owner, name } = options.repo;
|
|
52131
|
+
const head2 = `${owner}:${options.branch}`;
|
|
52132
|
+
const response = await withGithubRetries(
|
|
52133
|
+
"github pr list",
|
|
52134
|
+
async () => fetchImpl(`${baseUrl}/repos/${owner}/${name}/pulls?state=open&head=${encodeURIComponent(head2)}`, {
|
|
52135
|
+
method: "GET",
|
|
52136
|
+
headers: githubHeaders(options.credential)
|
|
52137
|
+
})
|
|
52138
|
+
);
|
|
52139
|
+
if (response.status !== 200) {
|
|
52140
|
+
return null;
|
|
52141
|
+
}
|
|
52142
|
+
const list = await response.json();
|
|
52143
|
+
if (!Array.isArray(list) || list.length === 0) {
|
|
52144
|
+
return null;
|
|
52145
|
+
}
|
|
52146
|
+
return toForgePullRequest(list[0], true);
|
|
52147
|
+
}
|
|
52148
|
+
async function openDraftPullRequest(options) {
|
|
52149
|
+
const baseUrl = (options.apiBaseUrl ?? GITHUB_API_BASE_URL).replace(/\/+$/, "");
|
|
52150
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
52151
|
+
const { owner, name } = options.repo;
|
|
52152
|
+
const created = await withGithubRetries(
|
|
52153
|
+
"github pr create",
|
|
52154
|
+
async () => fetchImpl(`${baseUrl}/repos/${owner}/${name}/pulls`, {
|
|
52155
|
+
method: "POST",
|
|
52156
|
+
headers: githubHeaders(options.credential),
|
|
52157
|
+
body: JSON.stringify({
|
|
52158
|
+
title: draftPrTitle(options),
|
|
52159
|
+
head: options.branch,
|
|
52160
|
+
base: options.repo.default_branch,
|
|
52161
|
+
body: draftPrBody(options),
|
|
52162
|
+
draft: true,
|
|
52163
|
+
maintainer_can_modify: true
|
|
52164
|
+
})
|
|
52165
|
+
})
|
|
52166
|
+
);
|
|
52167
|
+
if (created.status === 201) {
|
|
52168
|
+
return toForgePullRequest(await created.json(), false);
|
|
52169
|
+
}
|
|
52170
|
+
if (created.status === 422) {
|
|
52171
|
+
const detail = await readErrorText(created);
|
|
52172
|
+
if (/already exists/i.test(detail)) {
|
|
52173
|
+
const existing = await adoptExistingPullRequest(baseUrl, fetchImpl, options);
|
|
52174
|
+
if (existing) {
|
|
52175
|
+
return existing;
|
|
52176
|
+
}
|
|
52177
|
+
}
|
|
52178
|
+
throw new Error(`github pr create failed 422: ${redactSecrets(detail).slice(0, 500)}`);
|
|
52179
|
+
}
|
|
52180
|
+
throw new Error(`github pr create failed ${created.status}: ${redactSecrets(await readErrorText(created)).slice(0, 500)}`);
|
|
52181
|
+
}
|
|
52049
52182
|
async function removeWorktree(baseRepo, worktreeDir) {
|
|
52050
52183
|
try {
|
|
52051
52184
|
await runGit(["worktree", "remove", "--force", worktreeDir], baseRepo);
|
|
@@ -52807,7 +52940,13 @@ async function executeClaimedUnit(fetchImpl, appUrl2, state, config2, io, runtim
|
|
|
52807
52940
|
status: result.ok ? "succeeded" : "failed",
|
|
52808
52941
|
summary: result.summary,
|
|
52809
52942
|
log_ref: input.logRef(id),
|
|
52810
|
-
model: (turnRuntime ?? runtime) === "codex" ? "codex-cli" : "claude-cli"
|
|
52943
|
+
model: (turnRuntime ?? runtime) === "codex" ? "codex-cli" : "claude-cli",
|
|
52944
|
+
// Artifact-bearing result fields (T1.5) — only sent when the harness produced them, so
|
|
52945
|
+
// the result route's `.strict()` schema still accepts a plain read-status report.
|
|
52946
|
+
...result.prUrl ? { pr_url: result.prUrl } : {},
|
|
52947
|
+
...result.branch ? { branch: result.branch } : {},
|
|
52948
|
+
...result.commitSha ? { commit_sha: result.commitSha } : {},
|
|
52949
|
+
...result.evidence && result.evidence.length > 0 ? { evidence: result.evidence } : {}
|
|
52811
52950
|
}, state.runner_secret);
|
|
52812
52951
|
if (reported.status !== 200) {
|
|
52813
52952
|
throw new Error(`${claimedUnitLabel(input.kind)} result failed ${reported.status}: ${redactForLog(JSON.stringify(reported.json))}`);
|
|
@@ -52981,14 +53120,23 @@ async function prepareForgeTurn(ctx, workOrder, execution) {
|
|
|
52981
53120
|
],
|
|
52982
53121
|
allowNetwork: ctx.config.sandboxAllowNetwork
|
|
52983
53122
|
});
|
|
52984
|
-
return {
|
|
53123
|
+
return {
|
|
53124
|
+
ok: true,
|
|
53125
|
+
prep: {
|
|
53126
|
+
workspace,
|
|
53127
|
+
credential: { token, expiresAt, canPush },
|
|
53128
|
+
sandbox,
|
|
53129
|
+
repoDir: workspace.worktreeDir,
|
|
53130
|
+
repo: { owner, name, default_branch: defaultBranch },
|
|
53131
|
+
buildRequestId
|
|
53132
|
+
}
|
|
53133
|
+
};
|
|
52985
53134
|
}
|
|
52986
53135
|
async function finalizeForgeBuildPush(prep, result) {
|
|
53136
|
+
const credential = { token: prep.credential.token, expiresAt: prep.credential.expiresAt };
|
|
53137
|
+
let pushed;
|
|
52987
53138
|
try {
|
|
52988
|
-
|
|
52989
|
-
const note = pushed ? `[forge] pushed ${pushed.commitSha} to ${prep.workspace.branch}` : "[forge] no changes to push";
|
|
52990
|
-
return { ...result, summary: `${result.summary}
|
|
52991
|
-
${note}`.slice(0, 12e3) };
|
|
53139
|
+
pushed = await pushChangeset(prep.workspace, credential);
|
|
52992
53140
|
} catch (error51) {
|
|
52993
53141
|
return {
|
|
52994
53142
|
...result,
|
|
@@ -52997,6 +53145,43 @@ ${note}`.slice(0, 12e3) };
|
|
|
52997
53145
|
[forge] push failed: ${redactForLog(error51 instanceof Error ? error51.message : String(error51))}`.slice(0, 12e3)
|
|
52998
53146
|
};
|
|
52999
53147
|
}
|
|
53148
|
+
if (!pushed) {
|
|
53149
|
+
return { ...result, summary: `${result.summary}
|
|
53150
|
+
[forge] no changes to push`.slice(0, 12e3) };
|
|
53151
|
+
}
|
|
53152
|
+
try {
|
|
53153
|
+
const pr = await openDraftPullRequest({
|
|
53154
|
+
repo: prep.repo,
|
|
53155
|
+
branch: prep.workspace.branch,
|
|
53156
|
+
buildRequestId: prep.buildRequestId,
|
|
53157
|
+
commitSha: pushed.commitSha,
|
|
53158
|
+
credential
|
|
53159
|
+
});
|
|
53160
|
+
const evidence = [
|
|
53161
|
+
{ kind: "note", summary: `pushed ${pushed.commitSha} to ${prep.workspace.branch}`.slice(0, 500) },
|
|
53162
|
+
{ kind: "note", summary: `${pr.adopted ? "adopted existing" : "opened"} draft PR ${pr.url}`.slice(0, 500) }
|
|
53163
|
+
];
|
|
53164
|
+
return {
|
|
53165
|
+
...result,
|
|
53166
|
+
prUrl: pr.url,
|
|
53167
|
+
branch: prep.workspace.branch,
|
|
53168
|
+
commitSha: pushed.commitSha,
|
|
53169
|
+
evidence,
|
|
53170
|
+
summary: `${result.summary}
|
|
53171
|
+
[forge] pushed ${pushed.commitSha} to ${prep.workspace.branch}; ${pr.adopted ? "adopted" : "opened"} draft PR ${pr.url}`.slice(0, 12e3)
|
|
53172
|
+
};
|
|
53173
|
+
} catch (error51) {
|
|
53174
|
+
return {
|
|
53175
|
+
...result,
|
|
53176
|
+
ok: false,
|
|
53177
|
+
// The branch reached GitHub but the draft PR did not — fail so the phase requeues
|
|
53178
|
+
// rather than advancing a headless push. Re-entry re-pushes (no-op) and re-opens (adopt).
|
|
53179
|
+
branch: prep.workspace.branch,
|
|
53180
|
+
commitSha: pushed.commitSha,
|
|
53181
|
+
summary: `${result.summary}
|
|
53182
|
+
[forge] pushed ${pushed.commitSha} to ${prep.workspace.branch}; draft PR open failed: ${redactForLog(error51 instanceof Error ? error51.message : String(error51))}`.slice(0, 12e3)
|
|
53183
|
+
};
|
|
53184
|
+
}
|
|
53000
53185
|
}
|
|
53001
53186
|
function buildTurnPrompt(input) {
|
|
53002
53187
|
const { kind, workOrder, execution } = input;
|
|
@@ -53019,12 +53204,12 @@ function buildTurnPrompt(input) {
|
|
|
53019
53204
|
const isForgeReview = execution?.profile === "forge_review";
|
|
53020
53205
|
const isSeatWork = execution?.profile === "seat_work";
|
|
53021
53206
|
return [
|
|
53022
|
-
hasForgeContext ? `Call rost_get_context first to load your full ${cliBrand.name} charter,
|
|
53207
|
+
hasForgeContext ? `Call rost_get_context first to load your full ${cliBrand.name} charter, then call rost_get_build_context with forge.phase_run_id from the claimed context to load the approved plan, open findings, prior phase summaries, and remaining budgets. Next call rost_list_my_skills and load any assigned Skill you need with rost_get_my_skill_file. Then perform the assigned phase work, address every open finding, report a concise phase status, and stop.` : hasAicosTurnContext ? `Call rost_get_context first to load your full ${cliBrand.name} charter, then call rost_aicos_turn_load_context with turn_execution_id from the claimed context. Answer the AICOS user turn using only that loaded context plus seat-authorized tools. Return only the final concise Markdown answer; no hidden reasoning, tool chatter, raw JSON, secrets, local paths, or unauthorized memory.` : hasAicosContext ? `Call rost_get_context first to load your full ${cliBrand.name} charter, answer the AICOS user turn using only seat-authorized context and tools, return only the final answer as concise Markdown with short paragraphs or real lists, and stop.` : isSeatWork ? `Call rost_get_context first to load your full ${cliBrand.name} charter and current tasks, then carry out the scheduled work your charter authorizes \u2014 accept and complete assigned tasks, record signal readings, file friction, create or attach deliverables, and log your work through your seat tools. Every tool call is re-authorized server-side against your permission manifest, so use only the actions your charter grants and escalate anything beyond your autonomous scope. Report a concise status when done and stop.` : `Call rost_get_context first to load your full ${cliBrand.name} charter, report one read-only status, and stop.`,
|
|
53023
53208
|
// Forge workspace guidance (phase-specific). The harness owns all git network ops; the
|
|
53024
53209
|
// model never touches credentials or pushes.
|
|
53025
53210
|
input.hasWorkspace && isForgeBuild ? "A writable checkout of the repository is at your current working directory on the phase branch. Make the required code changes, run the project's build and tests with Bash, and commit locally. Do NOT run git push, git remote, or any network git command, and never request or handle GitHub tokens \u2014 the harness pushes your branch after you finish." : "",
|
|
53026
53211
|
input.hasWorkspace && isForgeReview ? "A READ-ONLY checkout of the repository is at your current working directory. Inspect the diff and source to review the assigned phase; do NOT modify, build, commit, or push anything." : "",
|
|
53027
|
-
input.hasWorkspace ? "
|
|
53212
|
+
input.hasWorkspace ? "Load your assigned Skills with rost_list_my_skills and rost_get_my_skill_file before starting; if none are assigned, proceed with your charter and the loaded build context." : "",
|
|
53028
53213
|
isSeatWork ? "If seat skill tools are available, load your assigned skills before starting; if none are exposed, proceed with your charter and assigned tasks." : "",
|
|
53029
53214
|
hasAicosTurnContext ? "For AICOS turns, the governed load tool returns the authoritative tenant clock, route context, transcript window, session summary, source counts, read models, and output contract. Never substitute local runtime time or model priors for that loaded tenant clock." : "",
|
|
53030
53215
|
hasAicosTenantClock ? "For AICOS turns, treat claimed work order context aicos.tenant_clock as the authoritative source for today's date, current time, timezone, and instant. Never substitute local runtime time or model priors for that queued tenant clock." : "",
|