@portel/photon 1.19.0 → 1.20.1
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/auto-ui/beam/routes/api-browse.d.ts.map +1 -1
- package/dist/auto-ui/beam/routes/api-browse.js +16 -4
- package/dist/auto-ui/beam/routes/api-browse.js.map +1 -1
- package/dist/auto-ui/beam/routes/api-config.d.ts.map +1 -1
- package/dist/auto-ui/beam/routes/api-config.js +165 -24
- package/dist/auto-ui/beam/routes/api-config.js.map +1 -1
- package/dist/auto-ui/beam/routes/api-marketplace.d.ts.map +1 -1
- package/dist/auto-ui/beam/routes/api-marketplace.js +14 -1
- package/dist/auto-ui/beam/routes/api-marketplace.js.map +1 -1
- package/dist/auto-ui/beam.d.ts.map +1 -1
- package/dist/auto-ui/beam.js +187 -77
- package/dist/auto-ui/beam.js.map +1 -1
- package/dist/auto-ui/bridge/index.d.ts.map +1 -1
- package/dist/auto-ui/bridge/index.js +17 -0
- package/dist/auto-ui/bridge/index.js.map +1 -1
- package/dist/auto-ui/bridge/renderers.d.ts.map +1 -1
- package/dist/auto-ui/bridge/renderers.js +12 -4
- package/dist/auto-ui/bridge/renderers.js.map +1 -1
- package/dist/auto-ui/streamable-http-transport.d.ts +1 -0
- package/dist/auto-ui/streamable-http-transport.d.ts.map +1 -1
- package/dist/auto-ui/streamable-http-transport.js +179 -44
- package/dist/auto-ui/streamable-http-transport.js.map +1 -1
- package/dist/auto-ui/types.d.ts +12 -0
- package/dist/auto-ui/types.d.ts.map +1 -1
- package/dist/auto-ui/types.js.map +1 -1
- package/dist/beam-form.bundle.js +63 -185
- package/dist/beam-form.bundle.js.map +4 -4
- package/dist/beam.bundle.js +2115 -761
- package/dist/beam.bundle.js.map +4 -4
- package/dist/capability-negotiator.d.ts +67 -0
- package/dist/capability-negotiator.d.ts.map +1 -0
- package/dist/capability-negotiator.js +104 -0
- package/dist/capability-negotiator.js.map +1 -0
- package/dist/channel-manager.d.ts +122 -0
- package/dist/channel-manager.d.ts.map +1 -0
- package/dist/channel-manager.js +266 -0
- package/dist/channel-manager.js.map +1 -0
- package/dist/cli/commands/beam.d.ts.map +1 -1
- package/dist/cli/commands/beam.js +47 -30
- package/dist/cli/commands/beam.js.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/build.js +27 -2
- package/dist/cli/commands/build.js.map +1 -1
- package/dist/cli/commands/daemon.d.ts.map +1 -1
- package/dist/cli/commands/daemon.js +12 -6
- package/dist/cli/commands/daemon.js.map +1 -1
- package/dist/cli/commands/mcp.d.ts.map +1 -1
- package/dist/cli/commands/mcp.js +18 -6
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/package.d.ts.map +1 -1
- package/dist/cli/commands/package.js +25 -7
- package/dist/cli/commands/package.js.map +1 -1
- package/dist/cli/commands/serve.d.ts.map +1 -1
- package/dist/cli/commands/serve.js +14 -2
- package/dist/cli/commands/serve.js.map +1 -1
- package/dist/cli-alias.d.ts.map +1 -1
- package/dist/cli-alias.js +2 -3
- package/dist/cli-alias.js.map +1 -1
- package/dist/context-store.d.ts +4 -4
- package/dist/context-store.d.ts.map +1 -1
- package/dist/context-store.js +18 -15
- package/dist/context-store.js.map +1 -1
- package/dist/context.d.ts +25 -2
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +69 -4
- package/dist/context.js.map +1 -1
- package/dist/daemon/client.d.ts.map +1 -1
- package/dist/daemon/client.js +16 -1
- package/dist/daemon/client.js.map +1 -1
- package/dist/daemon/manager.d.ts +2 -0
- package/dist/daemon/manager.d.ts.map +1 -1
- package/dist/daemon/manager.js +40 -8
- package/dist/daemon/manager.js.map +1 -1
- package/dist/daemon/server.js +89 -64
- package/dist/daemon/server.js.map +1 -1
- package/dist/daemon/worker-host.js +7 -0
- package/dist/daemon/worker-host.js.map +1 -1
- package/dist/daemon/worker-manager.d.ts.map +1 -1
- package/dist/daemon/worker-manager.js +79 -17
- package/dist/daemon/worker-manager.js.map +1 -1
- package/dist/daemon/worker-protocol.d.ts +3 -0
- package/dist/daemon/worker-protocol.d.ts.map +1 -1
- package/dist/deploy/cloudflare.d.ts.map +1 -1
- package/dist/deploy/cloudflare.js +2 -4
- package/dist/deploy/cloudflare.js.map +1 -1
- package/dist/loader.d.ts +11 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +129 -13
- package/dist/loader.js.map +1 -1
- package/dist/marketplace-manager.d.ts +7 -1
- package/dist/marketplace-manager.d.ts.map +1 -1
- package/dist/marketplace-manager.js +165 -61
- package/dist/marketplace-manager.js.map +1 -1
- package/dist/namespace-migration.d.ts +1 -0
- package/dist/namespace-migration.d.ts.map +1 -1
- package/dist/namespace-migration.js +86 -0
- package/dist/namespace-migration.js.map +1 -1
- package/dist/photon-cli-runner.d.ts.map +1 -1
- package/dist/photon-cli-runner.js +40 -21
- package/dist/photon-cli-runner.js.map +1 -1
- package/dist/photon-doc-extractor.d.ts.map +1 -1
- package/dist/photon-doc-extractor.js +59 -15
- package/dist/photon-doc-extractor.js.map +1 -1
- package/dist/resource-server.d.ts +105 -0
- package/dist/resource-server.d.ts.map +1 -0
- package/dist/resource-server.js +723 -0
- package/dist/resource-server.js.map +1 -0
- package/dist/serv/auth/jwt.d.ts +2 -0
- package/dist/serv/auth/jwt.d.ts.map +1 -1
- package/dist/serv/auth/jwt.js +11 -5
- package/dist/serv/auth/jwt.js.map +1 -1
- package/dist/serv/vault/token-vault.d.ts +2 -0
- package/dist/serv/vault/token-vault.d.ts.map +1 -1
- package/dist/serv/vault/token-vault.js +6 -0
- package/dist/serv/vault/token-vault.js.map +1 -1
- package/dist/server.d.ts +20 -149
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +246 -1233
- package/dist/server.js.map +1 -1
- package/dist/shared/audit.d.ts.map +1 -1
- package/dist/shared/audit.js +7 -0
- package/dist/shared/audit.js.map +1 -1
- package/dist/shared/security.d.ts +10 -0
- package/dist/shared/security.d.ts.map +1 -1
- package/dist/shared/security.js +27 -0
- package/dist/shared/security.js.map +1 -1
- package/dist/shared-utils.d.ts +4 -0
- package/dist/shared-utils.d.ts.map +1 -1
- package/dist/shared-utils.js +22 -0
- package/dist/shared-utils.js.map +1 -1
- package/dist/task-executor.d.ts +69 -0
- package/dist/task-executor.d.ts.map +1 -0
- package/dist/task-executor.js +182 -0
- package/dist/task-executor.js.map +1 -0
- package/dist/template-manager.d.ts.map +1 -1
- package/dist/template-manager.js +56 -234
- package/dist/template-manager.js.map +1 -1
- package/dist/types/photon-instance.d.ts +50 -0
- package/dist/types/photon-instance.d.ts.map +1 -0
- package/dist/types/photon-instance.js +9 -0
- package/dist/types/photon-instance.js.map +1 -0
- package/dist/types/server-types.d.ts +61 -0
- package/dist/types/server-types.d.ts.map +1 -0
- package/dist/types/server-types.js +8 -0
- package/dist/types/server-types.js.map +1 -0
- package/package.json +3 -3
|
@@ -5,13 +5,14 @@ import * as fs from 'fs/promises';
|
|
|
5
5
|
import * as path from 'path';
|
|
6
6
|
import * as os from 'os';
|
|
7
7
|
import { existsSync } from 'fs';
|
|
8
|
+
import { execFileSync } from 'child_process';
|
|
8
9
|
import { readText, readJSON, writeText, writeJSON } from './shared/io.js';
|
|
9
10
|
import * as crypto from 'crypto';
|
|
10
11
|
import { createLogger } from './shared/logger.js';
|
|
11
12
|
import { getErrorMessage } from './shared/error-handler.js';
|
|
12
13
|
import { verifyContentHash, validateAssetPath, isPathWithin } from './shared/security.js';
|
|
13
14
|
import { getDefaultContext } from './context.js';
|
|
14
|
-
import { getMetadataPath } from '@portel/photon-core';
|
|
15
|
+
import { getMetadataPath, resolvePath } from '@portel/photon-core';
|
|
15
16
|
import { SchemaExtractor } from '@portel/photon-core';
|
|
16
17
|
// Timeout for marketplace fetch requests
|
|
17
18
|
const FETCH_TIMEOUT_MS = 10 * 1000;
|
|
@@ -33,8 +34,11 @@ function getGitHubToken() {
|
|
|
33
34
|
_ghToken = process.env.GITHUB_TOKEN || null;
|
|
34
35
|
if (!_ghToken) {
|
|
35
36
|
try {
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
_ghToken =
|
|
38
|
+
execFileSync('gh', ['auth', 'token'], {
|
|
39
|
+
encoding: 'utf-8',
|
|
40
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
41
|
+
}).trim() || null;
|
|
38
42
|
}
|
|
39
43
|
catch {
|
|
40
44
|
_ghToken = null;
|
|
@@ -115,10 +119,11 @@ export async function calculatePhotonHash(sourceFilePath, assets, baseDir) {
|
|
|
115
119
|
/**
|
|
116
120
|
* Read local installation metadata
|
|
117
121
|
*/
|
|
118
|
-
export async function readLocalMetadata() {
|
|
122
|
+
export async function readLocalMetadata(baseDir) {
|
|
123
|
+
const metaFile = baseDir ? getMetadataPath(baseDir) : METADATA_FILE;
|
|
119
124
|
try {
|
|
120
|
-
if (existsSync(
|
|
121
|
-
return await readJSON(
|
|
125
|
+
if (existsSync(metaFile)) {
|
|
126
|
+
return await readJSON(metaFile);
|
|
122
127
|
}
|
|
123
128
|
}
|
|
124
129
|
catch (error) {
|
|
@@ -127,6 +132,11 @@ export async function readLocalMetadata() {
|
|
|
127
132
|
}
|
|
128
133
|
return { photons: {} };
|
|
129
134
|
}
|
|
135
|
+
function validateSafeName(name, label) {
|
|
136
|
+
if (/[;&|$`(){}\\\<>!#~\n\r]/.test(name)) {
|
|
137
|
+
throw new Error(`Invalid ${label}: contains unsafe characters`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
130
140
|
export class MarketplaceManager {
|
|
131
141
|
config = { marketplaces: [] };
|
|
132
142
|
logger;
|
|
@@ -732,7 +742,7 @@ export class MarketplaceManager {
|
|
|
732
742
|
* Safe to call on every startup — only fetches when assets are actually missing.
|
|
733
743
|
*/
|
|
734
744
|
async repairMissingAssets(workingDir) {
|
|
735
|
-
const localMetadata = await
|
|
745
|
+
const localMetadata = await this.readMetadata();
|
|
736
746
|
let repaired = 0;
|
|
737
747
|
for (const [fileName, installInfo] of Object.entries(localMetadata.photons)) {
|
|
738
748
|
const photonName = fileName.replace(/\.photon\.ts$/, '');
|
|
@@ -1143,7 +1153,7 @@ export class MarketplaceManager {
|
|
|
1143
1153
|
return { photons: {} };
|
|
1144
1154
|
}
|
|
1145
1155
|
async writeMetadata(metadata) {
|
|
1146
|
-
await fs.mkdir(this.
|
|
1156
|
+
await fs.mkdir(path.dirname(this.metadataFile), { recursive: true });
|
|
1147
1157
|
await writeJSON(this.metadataFile, metadata);
|
|
1148
1158
|
}
|
|
1149
1159
|
/**
|
|
@@ -1327,30 +1337,82 @@ export class MarketplaceManager {
|
|
|
1327
1337
|
* Shared logic used by both CLI and Beam.
|
|
1328
1338
|
*/
|
|
1329
1339
|
async forkPhoton(name, workingDir, options) {
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
if (
|
|
1340
|
+
validateSafeName(name, 'photon name');
|
|
1341
|
+
if (options?.targetRepo)
|
|
1342
|
+
validateSafeName(options.targetRepo, 'target repo');
|
|
1343
|
+
if (options?.createRepo)
|
|
1344
|
+
validateSafeName(options.createRepo, 'repo name');
|
|
1345
|
+
if (options?.newName)
|
|
1346
|
+
validateSafeName(options.newName, 'new photon name');
|
|
1347
|
+
const sourcePath = await resolvePath(name, workingDir);
|
|
1348
|
+
if (!sourcePath) {
|
|
1334
1349
|
return { success: false, message: `Photon not found: ${name}` };
|
|
1335
1350
|
}
|
|
1336
|
-
|
|
1337
|
-
const
|
|
1338
|
-
const
|
|
1339
|
-
|
|
1351
|
+
const sourceName = path.basename(sourcePath).replace(/\.photon\.(ts|js)$/, '');
|
|
1352
|
+
const normalizedSourceKey = this.toMetadataKey(sourcePath, workingDir);
|
|
1353
|
+
const requestedNewName = options?.newName?.trim();
|
|
1354
|
+
const localMetadata = await this.readMetadata();
|
|
1355
|
+
const installMeta = localMetadata.photons[normalizedSourceKey];
|
|
1356
|
+
const isLocalSource = !installMeta;
|
|
1357
|
+
const targetName = requestedNewName || sourceName;
|
|
1358
|
+
const suggestedName = `${sourceName}-copy`;
|
|
1359
|
+
if (isLocalSource && !requestedNewName) {
|
|
1340
1360
|
return {
|
|
1341
|
-
success:
|
|
1342
|
-
message: `${
|
|
1361
|
+
success: false,
|
|
1362
|
+
message: `${sourceName} is already local. Choose a new local name to fork it.`,
|
|
1363
|
+
requiresName: true,
|
|
1364
|
+
suggestedName,
|
|
1343
1365
|
};
|
|
1344
1366
|
}
|
|
1367
|
+
if (isLocalSource && requestedNewName === sourceName) {
|
|
1368
|
+
return {
|
|
1369
|
+
success: false,
|
|
1370
|
+
message: 'Forking a local photon requires a different new name.',
|
|
1371
|
+
requiresName: true,
|
|
1372
|
+
suggestedName,
|
|
1373
|
+
};
|
|
1374
|
+
}
|
|
1375
|
+
const targetPath = path.join(workingDir, `${targetName}.photon.ts`);
|
|
1376
|
+
const sourceRealPath = await fs.realpath(sourcePath).catch(() => sourcePath);
|
|
1377
|
+
const targetExists = existsSync(targetPath);
|
|
1378
|
+
const targetRealPath = targetExists
|
|
1379
|
+
? await fs.realpath(targetPath).catch(() => targetPath)
|
|
1380
|
+
: null;
|
|
1381
|
+
if (targetExists && targetRealPath !== sourceRealPath) {
|
|
1382
|
+
return {
|
|
1383
|
+
success: false,
|
|
1384
|
+
message: `A local photon named ${targetName} already exists. Choose a different local name.`,
|
|
1385
|
+
requiresName: true,
|
|
1386
|
+
suggestedName,
|
|
1387
|
+
};
|
|
1388
|
+
}
|
|
1389
|
+
const fileName = `${targetName}.photon.ts`;
|
|
1390
|
+
const filePath = targetPath;
|
|
1345
1391
|
// Check @forkedFrom tag
|
|
1346
|
-
const content = await readText(
|
|
1392
|
+
const content = await readText(sourcePath);
|
|
1347
1393
|
const hasForkedFrom = content.includes('@forkedFrom');
|
|
1394
|
+
const sourceAssetDir = path.join(path.dirname(sourcePath), sourceName);
|
|
1395
|
+
const targetAssetDir = path.join(workingDir, targetName);
|
|
1396
|
+
if (targetRealPath !== sourceRealPath && !isLocalSource) {
|
|
1397
|
+
await fs.mkdir(workingDir, { recursive: true });
|
|
1398
|
+
await fs.rename(sourcePath, targetPath);
|
|
1399
|
+
await this.movePhotonAssetDir(sourceAssetDir, targetAssetDir);
|
|
1400
|
+
}
|
|
1401
|
+
else if (targetRealPath !== sourceRealPath) {
|
|
1402
|
+
await fs.copyFile(sourcePath, targetPath);
|
|
1403
|
+
await this.copyPhotonAssetDir(sourceAssetDir, targetAssetDir);
|
|
1404
|
+
}
|
|
1405
|
+
else if (path.dirname(sourcePath) !== workingDir || targetName !== sourceName) {
|
|
1406
|
+
await fs.mkdir(workingDir, { recursive: true });
|
|
1407
|
+
await fs.rename(sourcePath, targetPath);
|
|
1408
|
+
await this.movePhotonAssetDir(sourceAssetDir, targetAssetDir);
|
|
1409
|
+
}
|
|
1348
1410
|
// Handle target repo push if specified
|
|
1349
1411
|
if (options?.targetRepo || options?.createRepo) {
|
|
1350
|
-
const {
|
|
1412
|
+
const { execFileSync } = await import('child_process');
|
|
1351
1413
|
// Check gh CLI
|
|
1352
1414
|
try {
|
|
1353
|
-
|
|
1415
|
+
execFileSync('gh', ['--version'], { stdio: 'pipe' });
|
|
1354
1416
|
}
|
|
1355
1417
|
catch {
|
|
1356
1418
|
return {
|
|
@@ -1361,7 +1423,9 @@ export class MarketplaceManager {
|
|
|
1361
1423
|
if (options.createRepo) {
|
|
1362
1424
|
// Create new repo and push
|
|
1363
1425
|
try {
|
|
1364
|
-
|
|
1426
|
+
execFileSync('gh', ['repo', 'create', options.createRepo, '--public', '--confirm'], {
|
|
1427
|
+
stdio: 'pipe',
|
|
1428
|
+
});
|
|
1365
1429
|
}
|
|
1366
1430
|
catch {
|
|
1367
1431
|
// Repo may already exist
|
|
@@ -1369,23 +1433,17 @@ export class MarketplaceManager {
|
|
|
1369
1433
|
const targetRepo = options.createRepo;
|
|
1370
1434
|
const tmpDir = path.join(os.tmpdir(), `photon-fork-${Date.now()}`);
|
|
1371
1435
|
try {
|
|
1372
|
-
|
|
1436
|
+
execFileSync('gh', ['repo', 'clone', targetRepo, tmpDir, '--', '--depth=1'], {
|
|
1373
1437
|
stdio: 'pipe',
|
|
1374
1438
|
});
|
|
1375
1439
|
await fs.copyFile(filePath, path.join(tmpDir, fileName));
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
await fs.mkdir(path.dirname(dstAsset), { recursive: true });
|
|
1384
|
-
await fs.copyFile(srcAsset, dstAsset);
|
|
1385
|
-
}
|
|
1386
|
-
}
|
|
1387
|
-
}
|
|
1388
|
-
execSync(`cd "${tmpDir}" && git add -A && git commit -m "fork: ${name} photon" && git push origin`, { stdio: 'pipe' });
|
|
1440
|
+
await this.copyPhotonAssetDir(targetAssetDir, path.join(tmpDir, targetName));
|
|
1441
|
+
execFileSync('git', ['add', '-A'], { cwd: tmpDir, stdio: 'pipe' });
|
|
1442
|
+
execFileSync('git', ['commit', '-m', `fork: ${name} photon`], {
|
|
1443
|
+
cwd: tmpDir,
|
|
1444
|
+
stdio: 'pipe',
|
|
1445
|
+
});
|
|
1446
|
+
execFileSync('git', ['push', 'origin'], { cwd: tmpDir, stdio: 'pipe' });
|
|
1389
1447
|
await fs.rm(tmpDir, { recursive: true, force: true }).catch(() => { });
|
|
1390
1448
|
}
|
|
1391
1449
|
catch (e) {
|
|
@@ -1400,23 +1458,17 @@ export class MarketplaceManager {
|
|
|
1400
1458
|
// Push to existing repo
|
|
1401
1459
|
const tmpDir = path.join(os.tmpdir(), `photon-fork-${Date.now()}`);
|
|
1402
1460
|
try {
|
|
1403
|
-
|
|
1461
|
+
execFileSync('gh', ['repo', 'clone', options.targetRepo, tmpDir, '--', '--depth=1'], {
|
|
1404
1462
|
stdio: 'pipe',
|
|
1405
1463
|
});
|
|
1406
1464
|
await fs.copyFile(filePath, path.join(tmpDir, fileName));
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
await fs.mkdir(path.dirname(dstAsset), { recursive: true });
|
|
1415
|
-
await fs.copyFile(srcAsset, dstAsset);
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
}
|
|
1419
|
-
execSync(`cd "${tmpDir}" && git add -A && git commit -m "fork: ${name} photon" && git push origin`, { stdio: 'pipe' });
|
|
1465
|
+
await this.copyPhotonAssetDir(targetAssetDir, path.join(tmpDir, targetName));
|
|
1466
|
+
execFileSync('git', ['add', '-A'], { cwd: tmpDir, stdio: 'pipe' });
|
|
1467
|
+
execFileSync('git', ['commit', '-m', `fork: ${name} photon`], {
|
|
1468
|
+
cwd: tmpDir,
|
|
1469
|
+
stdio: 'pipe',
|
|
1470
|
+
});
|
|
1471
|
+
execFileSync('git', ['push', 'origin'], { cwd: tmpDir, stdio: 'pipe' });
|
|
1420
1472
|
await fs.rm(tmpDir, { recursive: true, force: true }).catch(() => { });
|
|
1421
1473
|
}
|
|
1422
1474
|
catch (e) {
|
|
@@ -1429,22 +1481,59 @@ export class MarketplaceManager {
|
|
|
1429
1481
|
}
|
|
1430
1482
|
}
|
|
1431
1483
|
// Remove marketplace tracking
|
|
1432
|
-
|
|
1484
|
+
if (installMeta) {
|
|
1485
|
+
delete localMetadata.photons[normalizedSourceKey];
|
|
1486
|
+
}
|
|
1433
1487
|
await this.writeMetadata(localMetadata);
|
|
1434
1488
|
const parts = [];
|
|
1435
|
-
|
|
1489
|
+
if (targetName !== sourceName) {
|
|
1490
|
+
parts.push(`Created local fork ${targetName} from ${sourceName}`);
|
|
1491
|
+
}
|
|
1492
|
+
else {
|
|
1493
|
+
parts.push(`${sourceName} is now your own`);
|
|
1494
|
+
}
|
|
1436
1495
|
if (hasForkedFrom) {
|
|
1437
1496
|
parts.push('Origin preserved as @forkedFrom tag');
|
|
1438
1497
|
}
|
|
1439
|
-
|
|
1498
|
+
if (installMeta) {
|
|
1499
|
+
parts.push('Marketplace update tracking removed');
|
|
1500
|
+
}
|
|
1440
1501
|
return { success: true, message: parts.join('. ') };
|
|
1441
1502
|
}
|
|
1503
|
+
toMetadataKey(filePath, workingDir) {
|
|
1504
|
+
return path.relative(workingDir, filePath).split(path.sep).join('/');
|
|
1505
|
+
}
|
|
1506
|
+
async copyPhotonAssetDir(sourceDir, targetDir) {
|
|
1507
|
+
const stat = await fs.lstat(sourceDir).catch(() => null);
|
|
1508
|
+
if (!stat)
|
|
1509
|
+
return;
|
|
1510
|
+
if (stat.isSymbolicLink()) {
|
|
1511
|
+
const linkTarget = await fs.readlink(sourceDir);
|
|
1512
|
+
await fs.symlink(linkTarget, targetDir).catch(() => { });
|
|
1513
|
+
return;
|
|
1514
|
+
}
|
|
1515
|
+
if (!stat.isDirectory())
|
|
1516
|
+
return;
|
|
1517
|
+
await fs.cp(sourceDir, targetDir, { recursive: true, force: true });
|
|
1518
|
+
}
|
|
1519
|
+
async movePhotonAssetDir(sourceDir, targetDir) {
|
|
1520
|
+
const stat = await fs.lstat(sourceDir).catch(() => null);
|
|
1521
|
+
if (!stat)
|
|
1522
|
+
return;
|
|
1523
|
+
if (existsSync(targetDir))
|
|
1524
|
+
return;
|
|
1525
|
+
await fs.mkdir(path.dirname(targetDir), { recursive: true });
|
|
1526
|
+
await fs.rename(sourceDir, targetDir);
|
|
1527
|
+
}
|
|
1442
1528
|
/**
|
|
1443
1529
|
* Contribute a photon back upstream via PR.
|
|
1444
1530
|
* Shared logic used by both CLI and Beam.
|
|
1445
1531
|
*/
|
|
1446
1532
|
async contributePhoton(name, workingDir, options) {
|
|
1447
|
-
|
|
1533
|
+
validateSafeName(name, 'photon name');
|
|
1534
|
+
if (options?.branch)
|
|
1535
|
+
validateSafeName(options.branch, 'branch name');
|
|
1536
|
+
const { execFileSync } = await import('child_process');
|
|
1448
1537
|
const fileName = `${name}.photon.ts`;
|
|
1449
1538
|
const filePath = path.join(workingDir, fileName);
|
|
1450
1539
|
// Check file exists
|
|
@@ -1453,7 +1542,7 @@ export class MarketplaceManager {
|
|
|
1453
1542
|
}
|
|
1454
1543
|
// Check gh CLI
|
|
1455
1544
|
try {
|
|
1456
|
-
|
|
1545
|
+
execFileSync('gh', ['--version'], { stdio: 'pipe' });
|
|
1457
1546
|
}
|
|
1458
1547
|
catch {
|
|
1459
1548
|
return {
|
|
@@ -1463,7 +1552,7 @@ export class MarketplaceManager {
|
|
|
1463
1552
|
}
|
|
1464
1553
|
// Check gh auth
|
|
1465
1554
|
try {
|
|
1466
|
-
|
|
1555
|
+
execFileSync('gh', ['auth', 'status'], { stdio: 'pipe' });
|
|
1467
1556
|
}
|
|
1468
1557
|
catch {
|
|
1469
1558
|
return {
|
|
@@ -1512,20 +1601,20 @@ export class MarketplaceManager {
|
|
|
1512
1601
|
}
|
|
1513
1602
|
// Fork the repo
|
|
1514
1603
|
try {
|
|
1515
|
-
|
|
1604
|
+
execFileSync('gh', ['repo', 'fork', repo, '--clone=false'], { stdio: 'pipe' });
|
|
1516
1605
|
}
|
|
1517
1606
|
catch {
|
|
1518
1607
|
// Fork may already exist
|
|
1519
1608
|
}
|
|
1520
1609
|
// Get fork name
|
|
1521
|
-
const forkJson =
|
|
1610
|
+
const forkJson = execFileSync('gh', ['api', 'user'], { encoding: 'utf-8' });
|
|
1522
1611
|
const ghUser = JSON.parse(forkJson).login;
|
|
1523
1612
|
const repoName = repo.split('/')[1];
|
|
1524
1613
|
const forkRepo = `${ghUser}/${repoName}`;
|
|
1525
1614
|
// Clone to temp dir
|
|
1526
1615
|
const tmpDir = path.join(os.tmpdir(), `photon-contribute-${Date.now()}`);
|
|
1527
1616
|
try {
|
|
1528
|
-
|
|
1617
|
+
execFileSync('gh', ['repo', 'clone', forkRepo, tmpDir, '--', '--depth=1'], {
|
|
1529
1618
|
stdio: 'pipe',
|
|
1530
1619
|
});
|
|
1531
1620
|
// Copy modified photon file
|
|
@@ -1543,9 +1632,24 @@ export class MarketplaceManager {
|
|
|
1543
1632
|
}
|
|
1544
1633
|
}
|
|
1545
1634
|
// Create branch, commit, push
|
|
1546
|
-
|
|
1635
|
+
execFileSync('git', ['checkout', '-b', branchName], { cwd: tmpDir, stdio: 'pipe' });
|
|
1636
|
+
execFileSync('git', ['add', '-A'], { cwd: tmpDir, stdio: 'pipe' });
|
|
1637
|
+
execFileSync('git', ['commit', '-m', `improve: update ${name} photon`], {
|
|
1638
|
+
cwd: tmpDir,
|
|
1639
|
+
stdio: 'pipe',
|
|
1640
|
+
});
|
|
1641
|
+
execFileSync('git', ['push', 'origin', branchName], { cwd: tmpDir, stdio: 'pipe' });
|
|
1547
1642
|
// Create PR
|
|
1548
|
-
const prOutput =
|
|
1643
|
+
const prOutput = execFileSync('gh', [
|
|
1644
|
+
'pr',
|
|
1645
|
+
'create',
|
|
1646
|
+
'--repo',
|
|
1647
|
+
repo,
|
|
1648
|
+
'--title',
|
|
1649
|
+
`Improve ${name} photon`,
|
|
1650
|
+
'--body',
|
|
1651
|
+
`Contributed improvements to ${name} photon via Photon marketplace.`,
|
|
1652
|
+
], { cwd: tmpDir, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
|
|
1549
1653
|
// Cleanup temp dir
|
|
1550
1654
|
await fs.rm(tmpDir, { recursive: true, force: true }).catch(() => { });
|
|
1551
1655
|
const prUrl = prOutput.trim();
|