Spaces:
Running
Running
Deploy ce29b5c to Docker Space
Browse filesSource: MisonL/gpt-image-playground-customer@ce29b5c26187210528cd5ad0057746d85b048249
public/hf-space-deploy-marker.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
{
|
| 2 |
"schema_version": 1,
|
| 3 |
-
"local_sha": "
|
| 4 |
-
"created_at": "2026-06-
|
| 5 |
}
|
|
|
|
| 1 |
{
|
| 2 |
"schema_version": 1,
|
| 3 |
+
"local_sha": "ce29b5c26187210528cd5ad0057746d85b048249",
|
| 4 |
+
"created_at": "2026-06-20T13:36:17.547Z"
|
| 5 |
}
|
scripts/agent-skill-scripts.test.mjs
CHANGED
|
@@ -3234,6 +3234,8 @@ describe('Agent skill script argument validation', () => {
|
|
| 3234 |
assert.match(skillText, /\.env\.agent\.local\.example/);
|
| 3235 |
assert.match(skillText, /page_sse_real_smoke_status/);
|
| 3236 |
assert.match(skillText, /responses_image_backend_real_smoke_status/);
|
|
|
|
|
|
|
| 3237 |
assert.match(skillText, /summary\.responses_page_sse_generate_smoke/);
|
| 3238 |
assert.match(skillText, /summary\.real_smoke_checks/);
|
| 3239 |
assert.match(apiReference, /npm run first-run/);
|
|
@@ -3242,6 +3244,8 @@ describe('Agent skill script argument validation', () => {
|
|
| 3242 |
assert.match(apiReference, /\.env\.agent\.local\.example/);
|
| 3243 |
assert.match(apiReference, /page_sse_real_smoke_status/);
|
| 3244 |
assert.match(apiReference, /responses_image_backend_real_smoke_status/);
|
|
|
|
|
|
|
| 3245 |
assert.match(apiReference, /summary\.responses_page_sse_generate_smoke/);
|
| 3246 |
assert.match(apiReference, /summary\.real_smoke_checks/);
|
| 3247 |
assert.match(readmeText, /不要手动并行启动多个单张脚本/);
|
|
|
|
| 3234 |
assert.match(skillText, /\.env\.agent\.local\.example/);
|
| 3235 |
assert.match(skillText, /page_sse_real_smoke_status/);
|
| 3236 |
assert.match(skillText, /responses_image_backend_real_smoke_status/);
|
| 3237 |
+
assert.match(skillText, /summary\.page_sse_real_smoke/);
|
| 3238 |
+
assert.match(skillText, /兼容聚合状态/);
|
| 3239 |
assert.match(skillText, /summary\.responses_page_sse_generate_smoke/);
|
| 3240 |
assert.match(skillText, /summary\.real_smoke_checks/);
|
| 3241 |
assert.match(apiReference, /npm run first-run/);
|
|
|
|
| 3244 |
assert.match(apiReference, /\.env\.agent\.local\.example/);
|
| 3245 |
assert.match(apiReference, /page_sse_real_smoke_status/);
|
| 3246 |
assert.match(apiReference, /responses_image_backend_real_smoke_status/);
|
| 3247 |
+
assert.match(apiReference, /summary\.page_sse_real_smoke/);
|
| 3248 |
+
assert.match(apiReference, /兼容聚合状态/);
|
| 3249 |
assert.match(apiReference, /summary\.responses_page_sse_generate_smoke/);
|
| 3250 |
assert.match(apiReference, /summary\.real_smoke_checks/);
|
| 3251 |
assert.match(readmeText, /不要手动并行启动多个单张脚本/);
|
scripts/command-center.test.mjs
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
| 18 |
import { buildFirstRunReport, formatFirstRunText } from './first-run.mjs';
|
| 19 |
import {
|
| 20 |
buildAdminCommands,
|
|
|
|
| 21 |
buildImageUpstreamRealSmokeStatus,
|
| 22 |
parseGitStatusEntries,
|
| 23 |
readStatusEnvFromFiles,
|
|
@@ -221,6 +222,83 @@ describe('Command center scripts', () => {
|
|
| 221 |
assert.doesNotMatch(JSON.stringify(status), /user:pass|original\.example|token=secret|original-secret/);
|
| 222 |
});
|
| 223 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 224 |
it('loads independent image upstream smoke readiness from env files without overriding shell env', async () => {
|
| 225 |
const tempDir = await mkdtemp(path.join(os.tmpdir(), 'image-upstream-status-'));
|
| 226 |
const localEnvPath = path.join(tempDir, '.env.local');
|
|
@@ -962,12 +1040,13 @@ describe('Command center scripts', () => {
|
|
| 962 |
assert.equal(body.summary.real_smoke_checks.agent_generate_1k, 'passed');
|
| 963 |
assert.equal(body.summary.real_smoke_checks.responses_page_sse_generate_1k, 'failed');
|
| 964 |
assert.equal(body.summary.real_smoke_checks.page_sse_edit_2k, 'skipped');
|
| 965 |
-
|
| 966 |
-
|
| 967 |
-
|
| 968 |
-
|
| 969 |
-
|
| 970 |
-
);
|
|
|
|
| 971 |
}
|
| 972 |
);
|
| 973 |
});
|
|
|
|
| 18 |
import { buildFirstRunReport, formatFirstRunText } from './first-run.mjs';
|
| 19 |
import {
|
| 20 |
buildAdminCommands,
|
| 21 |
+
buildImageUpstreamLocalEndpointStatus,
|
| 22 |
buildImageUpstreamRealSmokeStatus,
|
| 23 |
parseGitStatusEntries,
|
| 24 |
readStatusEnvFromFiles,
|
|
|
|
| 222 |
assert.doesNotMatch(JSON.stringify(status), /user:pass|original\.example|token=secret|original-secret/);
|
| 223 |
});
|
| 224 |
|
| 225 |
+
it('checks local real smoke endpoints without exposing URL paths or credentials', async () => {
|
| 226 |
+
const status = await buildImageUpstreamLocalEndpointStatus(
|
| 227 |
+
{
|
| 228 |
+
IMAGE_REAL_SMOKE_ORIGINAL_BASE_URL: 'http://127.0.0.1:3010/v1?ignored=no',
|
| 229 |
+
IMAGE_REAL_SMOKE_ORIGINAL_API_KEY: 'original-secret',
|
| 230 |
+
IMAGE_REAL_SMOKE_GAOREN_BASE_URL: 'http://localhost:3001/v1',
|
| 231 |
+
IMAGE_REAL_SMOKE_GAOREN_API_KEY: 'gaoren-secret',
|
| 232 |
+
IMAGE_REAL_SMOKE_SUB2API_BASE_URL: 'https://sub2api.example/v1',
|
| 233 |
+
IMAGE_REAL_SMOKE_SUB2API_API_KEY: 'sub2api-secret'
|
| 234 |
+
},
|
| 235 |
+
{
|
| 236 |
+
probe: async (endpoint) => ({
|
| 237 |
+
ok: endpoint.port === 3001,
|
| 238 |
+
reason: endpoint.port === 3001 ? undefined : 'connection_refused'
|
| 239 |
+
})
|
| 240 |
+
}
|
| 241 |
+
);
|
| 242 |
+
|
| 243 |
+
assert.deepEqual(status, {
|
| 244 |
+
checked_count: 1,
|
| 245 |
+
unavailable_count: 0,
|
| 246 |
+
unavailable_cases: [],
|
| 247 |
+
results: [
|
| 248 |
+
{
|
| 249 |
+
id: 'gaoren-images-sse',
|
| 250 |
+
endpoint: 'localhost:3001',
|
| 251 |
+
ok: true
|
| 252 |
+
}
|
| 253 |
+
]
|
| 254 |
+
});
|
| 255 |
+
assert.doesNotMatch(JSON.stringify(status), /secret|\/v1|sub2api\.example|ignored=no/);
|
| 256 |
+
});
|
| 257 |
+
|
| 258 |
+
it('reports unavailable local real smoke endpoints by case id', async () => {
|
| 259 |
+
const status = await buildImageUpstreamLocalEndpointStatus(
|
| 260 |
+
{
|
| 261 |
+
IMAGE_REAL_SMOKE_SUB2API_BASE_URL: 'http://127.0.0.1:3021/v1',
|
| 262 |
+
IMAGE_REAL_SMOKE_SUB2API_API_KEY: 'sub2api-secret',
|
| 263 |
+
IMAGE_REAL_SMOKE_MATSCA_BASE_URL: 'http://[::1]:3090/v1',
|
| 264 |
+
IMAGE_REAL_SMOKE_MATSCA_API_KEY: 'matsca-secret'
|
| 265 |
+
},
|
| 266 |
+
{
|
| 267 |
+
probe: async (endpoint) => ({
|
| 268 |
+
ok: false,
|
| 269 |
+
reason: endpoint.port === 3021 ? 'connection_refused' : 'timeout'
|
| 270 |
+
})
|
| 271 |
+
}
|
| 272 |
+
);
|
| 273 |
+
|
| 274 |
+
assert.deepEqual(status, {
|
| 275 |
+
checked_count: 3,
|
| 276 |
+
unavailable_count: 3,
|
| 277 |
+
unavailable_cases: ['sub2api-images-sse', 'sub2api-responses-json', 'matsca-images-sse'],
|
| 278 |
+
results: [
|
| 279 |
+
{
|
| 280 |
+
id: 'sub2api-images-sse',
|
| 281 |
+
endpoint: '127.0.0.1:3021',
|
| 282 |
+
ok: false,
|
| 283 |
+
reason: 'connection_refused'
|
| 284 |
+
},
|
| 285 |
+
{
|
| 286 |
+
id: 'sub2api-responses-json',
|
| 287 |
+
endpoint: '127.0.0.1:3021',
|
| 288 |
+
ok: false,
|
| 289 |
+
reason: 'connection_refused'
|
| 290 |
+
},
|
| 291 |
+
{
|
| 292 |
+
id: 'matsca-images-sse',
|
| 293 |
+
endpoint: '::1:3090',
|
| 294 |
+
ok: false,
|
| 295 |
+
reason: 'timeout'
|
| 296 |
+
}
|
| 297 |
+
]
|
| 298 |
+
});
|
| 299 |
+
assert.doesNotMatch(JSON.stringify(status), /secret|\/v1/);
|
| 300 |
+
});
|
| 301 |
+
|
| 302 |
it('loads independent image upstream smoke readiness from env files without overriding shell env', async () => {
|
| 303 |
const tempDir = await mkdtemp(path.join(os.tmpdir(), 'image-upstream-status-'));
|
| 304 |
const localEnvPath = path.join(tempDir, '.env.local');
|
|
|
|
| 1040 |
assert.equal(body.summary.real_smoke_checks.agent_generate_1k, 'passed');
|
| 1041 |
assert.equal(body.summary.real_smoke_checks.responses_page_sse_generate_1k, 'failed');
|
| 1042 |
assert.equal(body.summary.real_smoke_checks.page_sse_edit_2k, 'skipped');
|
| 1043 |
+
const pageSseOutput = body.layers
|
| 1044 |
+
.find((layer) => layer.name === 'billable_smoke')
|
| 1045 |
+
.checks.find((check) => check.name === 'responses_page_sse_generate_1k').output;
|
| 1046 |
+
const pageSseFailure = parseJsonPayload(pageSseOutput, 'responses page SSE doctor smoke');
|
| 1047 |
+
assert.equal(pageSseFailure.summary.selected_channel_id, null);
|
| 1048 |
+
assert.equal(pageSseFailure.summary.upstream_host, null);
|
| 1049 |
+
assert.match(pageSseOutput, /503 Service temporarily unavailable/);
|
| 1050 |
}
|
| 1051 |
);
|
| 1052 |
});
|
scripts/status.mjs
CHANGED
|
@@ -1,11 +1,13 @@
|
|
| 1 |
#!/usr/bin/env node
|
| 2 |
|
| 3 |
import { existsSync, readFileSync } from 'node:fs';
|
|
|
|
| 4 |
|
| 5 |
import { HF_SPACE_ID, HF_SPACE_URL } from './hf-space-doctor-utils.mjs';
|
| 6 |
import { isMainModule, parseJsonPayload, printJson, runCommand, runCommandStrict } from './command-center-utils.mjs';
|
| 7 |
|
| 8 |
const REMOTE_STATUS_TIMEOUT_MS = 30_000;
|
|
|
|
| 9 |
const IMAGE_UPSTREAM_REAL_SMOKE_CASES = [
|
| 10 |
{ id: 'original-images-json', prefix: 'IMAGE_REAL_SMOKE_ORIGINAL' },
|
| 11 |
{ id: 'gaoren-images-sse', prefix: 'IMAGE_REAL_SMOKE_GAOREN' },
|
|
@@ -127,6 +129,7 @@ function readTargetConfigured(testCase, env) {
|
|
| 127 |
const baseUrlError = baseUrl ? readBaseUrlValidationError(baseUrl.value) : undefined;
|
| 128 |
return {
|
| 129 |
baseUrl: Boolean(baseUrl),
|
|
|
|
| 130 |
apiKey: Boolean(apiKey),
|
| 131 |
responsesModel: Boolean(responsesModel),
|
| 132 |
invalidEnv: baseUrlError ? [{ key: baseUrl.key, reason: baseUrlError }] : []
|
|
@@ -175,6 +178,90 @@ export function buildImageUpstreamRealSmokeStatus(env = process.env) {
|
|
| 175 |
};
|
| 176 |
}
|
| 177 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 178 |
function parseArgs(argv) {
|
| 179 |
const unknown = argv.find((arg) => !['--help', '-h', '--remote'].includes(arg));
|
| 180 |
if (unknown) throw new Error(`Unknown option: ${unknown}`);
|
|
@@ -194,11 +281,13 @@ Options:
|
|
| 194 |
--help Show this help.`);
|
| 195 |
}
|
| 196 |
|
| 197 |
-
function buildLocalStatus() {
|
| 198 |
const packageJson = JSON.parse(readFileSync('package.json', 'utf8'));
|
| 199 |
const branch = runCommandStrict('git', ['branch', '--show-current']).trim();
|
| 200 |
const head = runCommandStrict('git', ['rev-parse', '--short', 'HEAD']).trim();
|
| 201 |
const changed = parseGitStatusEntries(runCommandStrict('git', ['status', '--porcelain=v1', '-z']));
|
|
|
|
|
|
|
| 202 |
return {
|
| 203 |
product: packageJson.name,
|
| 204 |
version: packageJson.version,
|
|
@@ -216,7 +305,10 @@ function buildLocalStatus() {
|
|
| 216 |
capabilities: '/api/agent/capabilities',
|
| 217 |
skill: 'skills/gpt-image-playground-agent/SKILL.md'
|
| 218 |
},
|
| 219 |
-
image_upstream_real_smoke:
|
|
|
|
|
|
|
|
|
|
| 220 |
};
|
| 221 |
}
|
| 222 |
|
|
@@ -244,14 +336,14 @@ function readRemoteStatus() {
|
|
| 244 |
);
|
| 245 |
}
|
| 246 |
|
| 247 |
-
function main() {
|
| 248 |
const options = parseArgs(process.argv.slice(2));
|
| 249 |
if (options.help) {
|
| 250 |
printHelp();
|
| 251 |
return;
|
| 252 |
}
|
| 253 |
|
| 254 |
-
const status = buildLocalStatus();
|
| 255 |
printJson({
|
| 256 |
ok: true,
|
| 257 |
...status,
|
|
@@ -259,9 +351,9 @@ function main() {
|
|
| 259 |
});
|
| 260 |
}
|
| 261 |
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
}
|
|
|
|
| 1 |
#!/usr/bin/env node
|
| 2 |
|
| 3 |
import { existsSync, readFileSync } from 'node:fs';
|
| 4 |
+
import net from 'node:net';
|
| 5 |
|
| 6 |
import { HF_SPACE_ID, HF_SPACE_URL } from './hf-space-doctor-utils.mjs';
|
| 7 |
import { isMainModule, parseJsonPayload, printJson, runCommand, runCommandStrict } from './command-center-utils.mjs';
|
| 8 |
|
| 9 |
const REMOTE_STATUS_TIMEOUT_MS = 30_000;
|
| 10 |
+
const LOCAL_ENDPOINT_TIMEOUT_MS = 500;
|
| 11 |
const IMAGE_UPSTREAM_REAL_SMOKE_CASES = [
|
| 12 |
{ id: 'original-images-json', prefix: 'IMAGE_REAL_SMOKE_ORIGINAL' },
|
| 13 |
{ id: 'gaoren-images-sse', prefix: 'IMAGE_REAL_SMOKE_GAOREN' },
|
|
|
|
| 129 |
const baseUrlError = baseUrl ? readBaseUrlValidationError(baseUrl.value) : undefined;
|
| 130 |
return {
|
| 131 |
baseUrl: Boolean(baseUrl),
|
| 132 |
+
baseUrlValue: baseUrl?.value,
|
| 133 |
apiKey: Boolean(apiKey),
|
| 134 |
responsesModel: Boolean(responsesModel),
|
| 135 |
invalidEnv: baseUrlError ? [{ key: baseUrl.key, reason: baseUrlError }] : []
|
|
|
|
| 178 |
};
|
| 179 |
}
|
| 180 |
|
| 181 |
+
function normalizeLocalHostname(hostname) {
|
| 182 |
+
return hostname.toLowerCase().replace(/^\[|\]$/g, '');
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
function isLocalHostname(hostname) {
|
| 186 |
+
const normalized = normalizeLocalHostname(hostname);
|
| 187 |
+
return normalized === 'localhost' || normalized === '127.0.0.1' || normalized === '::1';
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
function readUrlPort(url) {
|
| 191 |
+
if (url.port) return Number(url.port);
|
| 192 |
+
if (url.protocol === 'http:') return 80;
|
| 193 |
+
if (url.protocol === 'https:') return 443;
|
| 194 |
+
return undefined;
|
| 195 |
+
}
|
| 196 |
+
|
| 197 |
+
function readLocalEndpoint(testCase, env) {
|
| 198 |
+
const target = readTargetConfigured(testCase, env);
|
| 199 |
+
if (!target.baseUrlValue || target.invalidEnv.length > 0) return undefined;
|
| 200 |
+
const url = new URL(target.baseUrlValue);
|
| 201 |
+
if (!isLocalHostname(url.hostname)) return undefined;
|
| 202 |
+
const port = readUrlPort(url);
|
| 203 |
+
if (!port) return undefined;
|
| 204 |
+
return {
|
| 205 |
+
id: testCase.id,
|
| 206 |
+
host: normalizeLocalHostname(url.hostname),
|
| 207 |
+
port
|
| 208 |
+
};
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
function readLocalEndpointTargets(env) {
|
| 212 |
+
return IMAGE_UPSTREAM_REAL_SMOKE_CASES.map((testCase) => readLocalEndpoint(testCase, env)).filter(Boolean);
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
function formatEndpoint(endpoint) {
|
| 216 |
+
return `${endpoint.host}:${endpoint.port}`;
|
| 217 |
+
}
|
| 218 |
+
|
| 219 |
+
function readSocketFailureReason(error) {
|
| 220 |
+
if (error?.code === 'ECONNREFUSED') return 'connection_refused';
|
| 221 |
+
if (error?.code === 'ETIMEDOUT') return 'timeout';
|
| 222 |
+
if (error?.code === 'EHOSTUNREACH') return 'host_unreachable';
|
| 223 |
+
if (error?.code === 'ENETUNREACH') return 'network_unreachable';
|
| 224 |
+
return 'connection_failed';
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
function probeTcpEndpoint(endpoint, options = {}) {
|
| 228 |
+
const timeoutMs = options.timeoutMs || LOCAL_ENDPOINT_TIMEOUT_MS;
|
| 229 |
+
return new Promise((resolve) => {
|
| 230 |
+
const socket = net.createConnection({ host: endpoint.host, port: endpoint.port });
|
| 231 |
+
let settled = false;
|
| 232 |
+
const finish = (result) => {
|
| 233 |
+
if (settled) return;
|
| 234 |
+
settled = true;
|
| 235 |
+
socket.destroy();
|
| 236 |
+
resolve(result);
|
| 237 |
+
};
|
| 238 |
+
socket.setTimeout(timeoutMs, () => finish({ ok: false, reason: 'timeout' }));
|
| 239 |
+
socket.once('connect', () => finish({ ok: true }));
|
| 240 |
+
socket.once('error', (error) => finish({ ok: false, reason: readSocketFailureReason(error) }));
|
| 241 |
+
});
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
export async function buildImageUpstreamLocalEndpointStatus(env = process.env, options = {}) {
|
| 245 |
+
const probe = options.probe || probeTcpEndpoint;
|
| 246 |
+
const results = [];
|
| 247 |
+
for (const endpoint of readLocalEndpointTargets(env)) {
|
| 248 |
+
const result = await probe(endpoint, options);
|
| 249 |
+
results.push({
|
| 250 |
+
id: endpoint.id,
|
| 251 |
+
endpoint: formatEndpoint(endpoint),
|
| 252 |
+
ok: result.ok === true,
|
| 253 |
+
...(result.ok === true ? {} : { reason: result.reason || 'connection_failed' })
|
| 254 |
+
});
|
| 255 |
+
}
|
| 256 |
+
const unavailable = results.filter((item) => !item.ok);
|
| 257 |
+
return {
|
| 258 |
+
checked_count: results.length,
|
| 259 |
+
unavailable_count: unavailable.length,
|
| 260 |
+
unavailable_cases: unavailable.map((item) => item.id),
|
| 261 |
+
results
|
| 262 |
+
};
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
function parseArgs(argv) {
|
| 266 |
const unknown = argv.find((arg) => !['--help', '-h', '--remote'].includes(arg));
|
| 267 |
if (unknown) throw new Error(`Unknown option: ${unknown}`);
|
|
|
|
| 281 |
--help Show this help.`);
|
| 282 |
}
|
| 283 |
|
| 284 |
+
async function buildLocalStatus() {
|
| 285 |
const packageJson = JSON.parse(readFileSync('package.json', 'utf8'));
|
| 286 |
const branch = runCommandStrict('git', ['branch', '--show-current']).trim();
|
| 287 |
const head = runCommandStrict('git', ['rev-parse', '--short', 'HEAD']).trim();
|
| 288 |
const changed = parseGitStatusEntries(runCommandStrict('git', ['status', '--porcelain=v1', '-z']));
|
| 289 |
+
const statusEnv = readStatusEnvFromFiles(process.env);
|
| 290 |
+
const imageUpstreamRealSmoke = buildImageUpstreamRealSmokeStatus(statusEnv);
|
| 291 |
return {
|
| 292 |
product: packageJson.name,
|
| 293 |
version: packageJson.version,
|
|
|
|
| 305 |
capabilities: '/api/agent/capabilities',
|
| 306 |
skill: 'skills/gpt-image-playground-agent/SKILL.md'
|
| 307 |
},
|
| 308 |
+
image_upstream_real_smoke: {
|
| 309 |
+
...imageUpstreamRealSmoke,
|
| 310 |
+
local_endpoint_checks: await buildImageUpstreamLocalEndpointStatus(statusEnv)
|
| 311 |
+
}
|
| 312 |
};
|
| 313 |
}
|
| 314 |
|
|
|
|
| 336 |
);
|
| 337 |
}
|
| 338 |
|
| 339 |
+
async function main() {
|
| 340 |
const options = parseArgs(process.argv.slice(2));
|
| 341 |
if (options.help) {
|
| 342 |
printHelp();
|
| 343 |
return;
|
| 344 |
}
|
| 345 |
|
| 346 |
+
const status = await buildLocalStatus();
|
| 347 |
printJson({
|
| 348 |
ok: true,
|
| 349 |
...status,
|
|
|
|
| 351 |
});
|
| 352 |
}
|
| 353 |
|
| 354 |
+
if (isMainModule(import.meta.url, process.argv[1])) {
|
| 355 |
+
main().catch((error) => {
|
| 356 |
+
printJson({ ok: false, error: error instanceof Error ? error.message : String(error) });
|
| 357 |
+
process.exit(1);
|
| 358 |
+
});
|
| 359 |
}
|
skills/gpt-image-playground-agent/SKILL.md
CHANGED
|
@@ -139,6 +139,7 @@ Authorization: Bearer <token>
|
|
| 139 |
| `summary.page_sse_auth_ready` | `agent:doctor` | 页面 SSE 鉴权是否已满足;为 `false` 时不要运行 `--page-sse` 真实计费请求。 |
|
| 140 |
| `page_sse_real_smoke_status` | `first-run --json` | 结构化说明 `first-run` 未执行真实 `/api/images` smoke;`state=not_run` 且 `billable=false` 表示它只是只读就绪检查。 |
|
| 141 |
| `responses_image_backend_real_smoke_status` | `first-run --json` | 结构化说明 `first-run` 未执行真实 Responses image_generation smoke;不要把声明支持当作实测通过。 |
|
|
|
|
| 142 |
| `summary.responses_page_sse_generate_smoke` | `agent:doctor` | `--allow-billable` 时对 `responses-image-generation` + page SSE + `responses-sse` 这条文生图路径的真实 smoke 状态;非计费时为 `skipped`。 |
|
| 143 |
| `summary.real_smoke_checks` | `agent:doctor` | 各真实 smoke 的状态汇总,包含 `agent_generate_1k`、`responses_page_sse_generate_1k`、`agent_edit_1k` 和 `page_sse_edit_2k`。 |
|
| 144 |
| `private_agent_env.exists` | `first-run --json` | 本机是否存在 `.env.agent.local` 私有配置;Agent CLI 默认从当前仓库根目录读取该文件。 |
|
|
|
|
| 139 |
| `summary.page_sse_auth_ready` | `agent:doctor` | 页面 SSE 鉴权是否已满足;为 `false` 时不要运行 `--page-sse` 真实计费请求。 |
|
| 140 |
| `page_sse_real_smoke_status` | `first-run --json` | 结构化说明 `first-run` 未执行真实 `/api/images` smoke;`state=not_run` 且 `billable=false` 表示它只是只读就绪检查。 |
|
| 141 |
| `responses_image_backend_real_smoke_status` | `first-run --json` | 结构化说明 `first-run` 未执行真实 Responses image_generation smoke;不要把声明支持当作实测通过。 |
|
| 142 |
+
| `summary.page_sse_real_smoke` | `agent:doctor` | Page SSE 真实 smoke 的兼容聚合状态;任一 Page SSE smoke 失败为 `failed`,任一通过且无失败为 `passed`,全部跳过为 `skipped`;精确判断优先看 `summary.real_smoke_checks`。 |
|
| 143 |
| `summary.responses_page_sse_generate_smoke` | `agent:doctor` | `--allow-billable` 时对 `responses-image-generation` + page SSE + `responses-sse` 这条文生图路径的真实 smoke 状态;非计费时为 `skipped`。 |
|
| 144 |
| `summary.real_smoke_checks` | `agent:doctor` | 各真实 smoke 的状态汇总,包含 `agent_generate_1k`、`responses_page_sse_generate_1k`、`agent_edit_1k` 和 `page_sse_edit_2k`。 |
|
| 145 |
| `private_agent_env.exists` | `first-run --json` | 本机是否存在 `.env.agent.local` 私有配置;Agent CLI 默认从当前仓库根目录读取该文件。 |
|
skills/gpt-image-playground-agent/references/api.md
CHANGED
|
@@ -554,6 +554,7 @@ node "<skill-root>/scripts/diagnose-request.mjs" --base-url https://your-space.h
|
|
| 554 |
| `summary.page_sse_auth_ready` | `agent:doctor` | 页面 SSE 鉴权是否已满足;为 `false` 时不要运行 `--page-sse` 真实计费请求。 |
|
| 555 |
| `page_sse_real_smoke_status` | `first-run --json` | 结构化说明 `first-run` 未执行真实 `/api/images` smoke;`state=not_run` 且 `billable=false` 表示它只是只读就绪检查。 |
|
| 556 |
| `responses_image_backend_real_smoke_status` | `first-run --json` | 结构化说明 `first-run` 未执行真实 Responses image_generation smoke;不要把声明支持当作实测通过。 |
|
|
|
|
| 557 |
| `summary.responses_page_sse_generate_smoke` | `agent:doctor` | `--allow-billable` 时对 `responses-image-generation` + page SSE + `responses-sse` 这条文生图路径的真实 smoke 状态;非计费时为 `skipped`。 |
|
| 558 |
| `summary.real_smoke_checks` | `agent:doctor` | 各真实 smoke 的状态汇总,包含 `agent_generate_1k`、`responses_page_sse_generate_1k`、`agent_edit_1k` 和 `page_sse_edit_2k`。 |
|
| 559 |
| `private_agent_env.exists` | `first-run --json` | 本机是否存在 `.env.agent.local` 私有配置;Agent CLI 默认从当前仓库根目录读取该文件。 |
|
|
|
|
| 554 |
| `summary.page_sse_auth_ready` | `agent:doctor` | 页面 SSE 鉴权是否已满足;为 `false` 时不要运行 `--page-sse` 真实计费请求。 |
|
| 555 |
| `page_sse_real_smoke_status` | `first-run --json` | 结构化说明 `first-run` 未执行真实 `/api/images` smoke;`state=not_run` 且 `billable=false` 表示它只是只读就绪检查。 |
|
| 556 |
| `responses_image_backend_real_smoke_status` | `first-run --json` | 结构化说明 `first-run` 未执行真实 Responses image_generation smoke;不要把声明支持当作实测通过。 |
|
| 557 |
+
| `summary.page_sse_real_smoke` | `agent:doctor` | Page SSE 真实 smoke 的兼容聚合状态;任一 Page SSE smoke 失败为 `failed`,任一通过且无失败为 `passed`,全部跳过为 `skipped`;精确判断优先看 `summary.real_smoke_checks`。 |
|
| 558 |
| `summary.responses_page_sse_generate_smoke` | `agent:doctor` | `--allow-billable` 时对 `responses-image-generation` + page SSE + `responses-sse` 这条文生图路径的真实 smoke 状态;非计费时为 `skipped`。 |
|
| 559 |
| `summary.real_smoke_checks` | `agent:doctor` | 各真实 smoke 的状态汇总,包含 `agent_generate_1k`、`responses_page_sse_generate_1k`、`agent_edit_1k` 和 `page_sse_edit_2k`。 |
|
| 560 |
| `private_agent_env.exists` | `first-run --json` | 本机是否存在 `.env.agent.local` 私有配置;Agent CLI 默认从当前仓库根目录读取该文件。 |
|