oasis_test 0.1.7 → 0.1.8
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/index.js +177 -32
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -16056,6 +16056,26 @@ function parsePlanningIssues(body) {
|
|
|
16056
16056
|
return [];
|
|
16057
16057
|
}
|
|
16058
16058
|
}
|
|
16059
|
+
function workorderSpecBody(spec) {
|
|
16060
|
+
return WORKORDER_SPEC_PREFIX + JSON.stringify(spec);
|
|
16061
|
+
}
|
|
16062
|
+
function parseWorkorderSpec(body) {
|
|
16063
|
+
const first = body.split("\n", 1)[0] ?? "";
|
|
16064
|
+
if (!first.startsWith(WORKORDER_SPEC_PREFIX)) return null;
|
|
16065
|
+
try {
|
|
16066
|
+
const parsed = JSON.parse(first.slice(WORKORDER_SPEC_PREFIX.length));
|
|
16067
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
16068
|
+
const out = {};
|
|
16069
|
+
if (typeof parsed.goal === "string" && parsed.goal.trim()) out.goal = parsed.goal.trim();
|
|
16070
|
+
if (Array.isArray(parsed.acceptanceCriteria)) {
|
|
16071
|
+
const items = parsed.acceptanceCriteria.filter((x) => typeof x === "string" && x.trim().length > 0).map((x) => x.trim());
|
|
16072
|
+
if (items.length > 0) out.acceptanceCriteria = items;
|
|
16073
|
+
}
|
|
16074
|
+
return out.goal !== void 0 || out.acceptanceCriteria !== void 0 ? out : null;
|
|
16075
|
+
} catch {
|
|
16076
|
+
return null;
|
|
16077
|
+
}
|
|
16078
|
+
}
|
|
16059
16079
|
async function buildDynamicWorkorderPlan(input) {
|
|
16060
16080
|
const schema = input.schema;
|
|
16061
16081
|
const schemaByName = new Map(schema.map((def) => [def.name, def]));
|
|
@@ -16088,6 +16108,15 @@ async function buildDynamicWorkorderPlan(input) {
|
|
|
16088
16108
|
description: input.description
|
|
16089
16109
|
}
|
|
16090
16110
|
];
|
|
16111
|
+
const spec = {};
|
|
16112
|
+
if (input.goal?.trim()) spec.goal = input.goal.trim();
|
|
16113
|
+
if (input.acceptanceCriteria?.length) {
|
|
16114
|
+
const items = input.acceptanceCriteria.map((x) => x.trim()).filter(Boolean);
|
|
16115
|
+
if (items.length > 0) spec.acceptanceCriteria = items;
|
|
16116
|
+
}
|
|
16117
|
+
if (spec.goal !== void 0 || spec.acceptanceCriteria !== void 0) {
|
|
16118
|
+
ops.push({ action: "annotate", artifactId: briefId, body: workorderSpecBody(spec), blocks: false });
|
|
16119
|
+
}
|
|
16091
16120
|
const spawned = [{ id: briefId, type: "brief", role: "pm", owner: briefOwner }];
|
|
16092
16121
|
const agentGraph = input.agentPlan ? normalizeAgentPlan(input.agentPlan, primaryType) : null;
|
|
16093
16122
|
if (input.agentPlan && !agentGraph) {
|
|
@@ -16420,7 +16449,7 @@ function artifactSlug(idOrWorkspace, description) {
|
|
|
16420
16449
|
const slug4 = source.trim().toLowerCase().replace(/^wo-/, "").replace(/[^a-z0-9\u4e00-\u9fa5]+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
|
|
16421
16450
|
return slug4 || `wo-${Date.now()}`;
|
|
16422
16451
|
}
|
|
16423
|
-
var PLANNING_ISSUES_PREFIX, DEFAULT_TYPES;
|
|
16452
|
+
var PLANNING_ISSUES_PREFIX, DEFAULT_TYPES, WORKORDER_SPEC_PREFIX;
|
|
16424
16453
|
var init_planner = __esm({
|
|
16425
16454
|
"../server/src/domains/collab/planner.ts"() {
|
|
16426
16455
|
"use strict";
|
|
@@ -16434,6 +16463,7 @@ var init_planner = __esm({
|
|
|
16434
16463
|
{ name: "dev", contentType: "code", ownerRole: "dev" },
|
|
16435
16464
|
{ name: "qa", contentType: "text", ownerRole: "qa" }
|
|
16436
16465
|
];
|
|
16466
|
+
WORKORDER_SPEC_PREFIX = "OASIS_WORKORDER_SPEC ";
|
|
16437
16467
|
}
|
|
16438
16468
|
});
|
|
16439
16469
|
|
|
@@ -16710,6 +16740,13 @@ async function runCommand(kernel, blobs, oplog, actor, command, args, ctx = {})
|
|
|
16710
16740
|
if ((createdViaArg ?? "manual-spawn") === "seed" && ctx.schema) {
|
|
16711
16741
|
const title = optStr(args, "title") ?? optStr(args, "description") ?? workspace;
|
|
16712
16742
|
const brief = optStr(args, "brief") ?? optStr(args, "body") ?? optStr(args, "description") ?? workspace;
|
|
16743
|
+
const goal = optStr(args, "goal");
|
|
16744
|
+
const rawCriteria = args["acceptance_criteria"] ?? args["acceptanceCriteria"];
|
|
16745
|
+
const acceptanceCriteria = Array.isArray(rawCriteria) ? rawCriteria.filter((x) => typeof x === "string" && x.trim().length > 0).map((x) => x.trim()) : void 0;
|
|
16746
|
+
const briefForPlanner = acceptanceCriteria && acceptanceCriteria.length > 0 ? `${brief}
|
|
16747
|
+
|
|
16748
|
+
\u9A8C\u6536\u6807\u51C6\uFF1A
|
|
16749
|
+
${acceptanceCriteria.map((c) => `- ${c}`).join("\n")}` : brief;
|
|
16713
16750
|
const agentIssues = [];
|
|
16714
16751
|
let agentPlan = null;
|
|
16715
16752
|
if (ctx.planWorkorderWithAgent) {
|
|
@@ -16724,7 +16761,7 @@ async function runCommand(kernel, blobs, oplog, actor, command, args, ctx = {})
|
|
|
16724
16761
|
requestedType: type,
|
|
16725
16762
|
workspace,
|
|
16726
16763
|
title,
|
|
16727
|
-
brief,
|
|
16764
|
+
brief: briefForPlanner,
|
|
16728
16765
|
artifactTypes: ctx.schema.map((def) => ({
|
|
16729
16766
|
name: def.name,
|
|
16730
16767
|
ownerRole: def.ownerRole,
|
|
@@ -16757,6 +16794,8 @@ async function runCommand(kernel, blobs, oplog, actor, command, args, ctx = {})
|
|
|
16757
16794
|
workspace,
|
|
16758
16795
|
title,
|
|
16759
16796
|
description: brief,
|
|
16797
|
+
...goal !== void 0 ? { goal } : {},
|
|
16798
|
+
...acceptanceCriteria && acceptanceCriteria.length > 0 ? { acceptanceCriteria } : {},
|
|
16760
16799
|
actor,
|
|
16761
16800
|
schema: ctx.schema,
|
|
16762
16801
|
...optStr(args, "id") !== void 0 ? { requestedArtifactId: optStr(args, "id") } : {},
|
|
@@ -18041,6 +18080,29 @@ function createNodeTokenStore(file) {
|
|
|
18041
18080
|
}
|
|
18042
18081
|
};
|
|
18043
18082
|
}
|
|
18083
|
+
function createEnrollTokenStore(defaultTtlMs = 30 * 60 * 1e3) {
|
|
18084
|
+
const table = /* @__PURE__ */ new Map();
|
|
18085
|
+
const prune = () => {
|
|
18086
|
+
const now = Date.now();
|
|
18087
|
+
for (const [token, entry] of table) if (entry.expiresAt <= now) table.delete(token);
|
|
18088
|
+
};
|
|
18089
|
+
return {
|
|
18090
|
+
issue(nodeId, ttlMs = defaultTtlMs) {
|
|
18091
|
+
prune();
|
|
18092
|
+
const token = `ent_${(0, import_node_crypto3.randomBytes)(24).toString("base64url")}`;
|
|
18093
|
+
const expiresAt = Date.now() + ttlMs;
|
|
18094
|
+
table.set(token, { nodeId, expiresAt });
|
|
18095
|
+
return { token, expiresAt: new Date(expiresAt).toISOString() };
|
|
18096
|
+
},
|
|
18097
|
+
consume(token) {
|
|
18098
|
+
prune();
|
|
18099
|
+
const entry = table.get(token);
|
|
18100
|
+
if (!entry) return null;
|
|
18101
|
+
table.delete(token);
|
|
18102
|
+
return { nodeId: entry.nodeId };
|
|
18103
|
+
}
|
|
18104
|
+
};
|
|
18105
|
+
}
|
|
18044
18106
|
var import_node_crypto3, fs;
|
|
18045
18107
|
var init_tokens = __esm({
|
|
18046
18108
|
"../server/src/tokens.ts"() {
|
|
@@ -19074,6 +19136,7 @@ function buildWorkorderSummaries(model, resolveActor, resolveProject) {
|
|
|
19074
19136
|
for (const [workspace, arts] of byWorkspace) {
|
|
19075
19137
|
const members = arts.map((a) => nodeInfo(model, a));
|
|
19076
19138
|
const seed = arts.find((a) => a.inputs.length === 0) ?? arts[0];
|
|
19139
|
+
const spec = workorderSpecOf(model, arts);
|
|
19077
19140
|
const concluded = members.filter((m) => m.concluded).length;
|
|
19078
19141
|
const lastOps = arts.map((a) => model.lastOpAt.get(a.id)).filter((t) => Boolean(t)).sort();
|
|
19079
19142
|
const participantIds = [...new Set(arts.map((a) => a.owner))];
|
|
@@ -19081,8 +19144,10 @@ function buildWorkorderSummaries(model, resolveActor, resolveProject) {
|
|
|
19081
19144
|
out.push({
|
|
19082
19145
|
id: workspace,
|
|
19083
19146
|
title: woTitle,
|
|
19084
|
-
//
|
|
19147
|
+
// 工单完整内容 = 根产物 description;仅当与标题不同(根产物有独立 title)时给出,避免与 title 重复
|
|
19085
19148
|
...seed.description && seed.description !== woTitle ? { description: seed.description } : {},
|
|
19149
|
+
// 一句话目标:优先取结构化 spec.goal;缺省时前端回退 description 首段(投影不替前端做回退,只给真值)
|
|
19150
|
+
...spec?.goal ? { goal: spec.goal } : {},
|
|
19086
19151
|
stage: deriveStage(members),
|
|
19087
19152
|
owner: ref(seed.owner),
|
|
19088
19153
|
participants: participantIds.map(ref),
|
|
@@ -19100,6 +19165,16 @@ function planningStatusOf(model, arts) {
|
|
|
19100
19165
|
const issues = [...model.annotations.values()].filter((annotation) => ids.has(annotation.anchor.target)).flatMap((annotation) => parsePlanningIssues(annotation.body));
|
|
19101
19166
|
return issues.length > 0 ? { status: "needs_staffing", issues } : { status: "ready", issues: [] };
|
|
19102
19167
|
}
|
|
19168
|
+
function workorderSpecOf(model, arts) {
|
|
19169
|
+
const seed = arts.find((a) => a.type === "brief") ?? arts.find((a) => a.inputs.length === 0);
|
|
19170
|
+
if (!seed) return null;
|
|
19171
|
+
for (const annotation of model.annotations.values()) {
|
|
19172
|
+
if (annotation.anchor.target !== seed.id) continue;
|
|
19173
|
+
const spec = parseWorkorderSpec(annotation.body);
|
|
19174
|
+
if (spec) return spec;
|
|
19175
|
+
}
|
|
19176
|
+
return null;
|
|
19177
|
+
}
|
|
19103
19178
|
var init_workorders = __esm({
|
|
19104
19179
|
"../server/src/domains/collab/workorders.ts"() {
|
|
19105
19180
|
"use strict";
|
|
@@ -27438,7 +27513,7 @@ Write-Host " Remove : Unregister-ScheduledTask -TaskName 'OasisNode-${p.nodeId}
|
|
|
27438
27513
|
}
|
|
27439
27514
|
function buildNpxCmd(p) {
|
|
27440
27515
|
const namePart = p.nodeName ? ` --name ${p.nodeName}` : "";
|
|
27441
|
-
return `npx -y oasis_test@latest start --server-ws ${p.gatewayUrl} --id ${p.nodeId}${namePart} --token ${p.token}`;
|
|
27516
|
+
return `npx -y oasis_test@latest start --server-ws ${p.gatewayUrl} --id ${p.nodeId}${namePart} --enroll-token ${p.token}`;
|
|
27442
27517
|
}
|
|
27443
27518
|
var init_connect_script = __esm({
|
|
27444
27519
|
"../server/src/domains/nodes/connect-script.ts"() {
|
|
@@ -27489,9 +27564,39 @@ function nodesDomain(deps) {
|
|
|
27489
27564
|
};
|
|
27490
27565
|
}
|
|
27491
27566
|
return (router) => {
|
|
27567
|
+
async function syncConnectedDaemon(daemonId, hub) {
|
|
27568
|
+
const d = hub.connectedDaemons().find((c) => c.daemonId === daemonId);
|
|
27569
|
+
if (!d) return;
|
|
27570
|
+
const existing = await deps.nodeStore.getNode(daemonId);
|
|
27571
|
+
await deps.nodeStore.upsertNode({
|
|
27572
|
+
id: daemonId,
|
|
27573
|
+
hostname: d.meta.hostname,
|
|
27574
|
+
nodeVersion: d.meta.nodeVersion ?? "unknown",
|
|
27575
|
+
status: "online",
|
|
27576
|
+
lastSeenAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
27577
|
+
enrolledAt: existing?.enrolledAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
27578
|
+
...d.meta.nodeName ? { name: d.meta.nodeName } : existing?.name ? { name: existing.name } : {}
|
|
27579
|
+
});
|
|
27580
|
+
const capabilities = d.meta.runtimes?.length ? d.meta.runtimes : d.meta.adapters.map((kind) => ({ kind, binary: void 0, version: void 0 }));
|
|
27581
|
+
for (const cap of capabilities) {
|
|
27582
|
+
await deps.nodeStore.upsertRuntime({
|
|
27583
|
+
id: `runtime:${daemonId}:${cap.kind}`,
|
|
27584
|
+
nodeId: daemonId,
|
|
27585
|
+
kind: cap.kind,
|
|
27586
|
+
hostname: d.meta.hostname,
|
|
27587
|
+
...cap.binary ? { binary: cap.binary } : {},
|
|
27588
|
+
...cap.version ? { version: cap.version } : {},
|
|
27589
|
+
status: "online",
|
|
27590
|
+
lastSeenAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
27591
|
+
});
|
|
27592
|
+
}
|
|
27593
|
+
}
|
|
27492
27594
|
router.get("/api/nodes", async () => {
|
|
27493
27595
|
const hub = deps.getHub();
|
|
27494
|
-
if (hub)
|
|
27596
|
+
if (hub) {
|
|
27597
|
+
wireHub(hub);
|
|
27598
|
+
await Promise.all(hub.connectedDaemons().map((d) => syncConnectedDaemon(d.daemonId, hub)));
|
|
27599
|
+
}
|
|
27495
27600
|
const nodes = await deps.nodeStore.listNodes();
|
|
27496
27601
|
const items = await Promise.all(nodes.map(async (n) => {
|
|
27497
27602
|
const rts = await deps.nodeStore.listRuntimes(n.id);
|
|
@@ -27518,7 +27623,10 @@ function nodesDomain(deps) {
|
|
|
27518
27623
|
});
|
|
27519
27624
|
router.get("/api/runtimes", async () => {
|
|
27520
27625
|
const hub = deps.getHub();
|
|
27521
|
-
if (hub)
|
|
27626
|
+
if (hub) {
|
|
27627
|
+
wireHub(hub);
|
|
27628
|
+
await Promise.all(hub.connectedDaemons().map((d) => syncConnectedDaemon(d.daemonId, hub)));
|
|
27629
|
+
}
|
|
27522
27630
|
const rts = await deps.nodeStore.listRuntimes();
|
|
27523
27631
|
const items = rts.map((r) => ({
|
|
27524
27632
|
id: r.id,
|
|
@@ -27535,28 +27643,28 @@ function nodesDomain(deps) {
|
|
|
27535
27643
|
});
|
|
27536
27644
|
router.post("/api/nodes/enroll", async (req) => {
|
|
27537
27645
|
const body = req.body ?? {};
|
|
27538
|
-
const requested = body.nodeId?.trim();
|
|
27539
|
-
const nodeId = requested || `node-${(0, import_node_crypto9.randomUUID)().slice(0, 8)}`;
|
|
27540
27646
|
const nodeName = body.nodeName?.trim() || void 0;
|
|
27541
|
-
|
|
27542
|
-
|
|
27543
|
-
}
|
|
27544
|
-
const
|
|
27647
|
+
const requestedId = body.nodeId?.trim();
|
|
27648
|
+
const existing = requestedId ? await deps.nodeStore.getNode(requestedId) : null;
|
|
27649
|
+
const nodeId = existing?.id ?? requestedId ?? `node-${(0, import_node_crypto9.randomUUID)().slice(0, 8)}`;
|
|
27650
|
+
const enroll = deps.enrollTokens.issue(nodeId);
|
|
27545
27651
|
if (nodeName) nodeNames.set(nodeId, nodeName);
|
|
27546
|
-
|
|
27547
|
-
|
|
27548
|
-
id: nodeId,
|
|
27549
|
-
name: nodeName,
|
|
27550
|
-
hostname: existing?.hostname ?? "unknown",
|
|
27551
|
-
nodeVersion: existing?.nodeVersion ?? "unknown",
|
|
27552
|
-
status: "offline",
|
|
27553
|
-
lastSeenAt: existing?.lastSeenAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
27554
|
-
enrolledAt: existing?.enrolledAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
27555
|
-
});
|
|
27556
|
-
const params = { gatewayUrl: deps.gatewayUrl, nodeId, token, repoRemote: deps.repoRemote };
|
|
27652
|
+
if (existing && nodeName) await deps.nodeStore.updateNodeName(nodeId, nodeName);
|
|
27653
|
+
const params = { gatewayUrl: deps.gatewayUrl, nodeId, token: enroll.token, repoRemote: deps.repoRemote };
|
|
27557
27654
|
const script = body.platform === "windows" ? buildWindowsConnectScript(params) : buildConnectScript(params);
|
|
27558
|
-
const npxCmd = buildNpxCmd({ gatewayUrl: deps.gatewayUrl, nodeId, token, nodeName });
|
|
27559
|
-
return { status: 200, body: { nodeId, nodeName, token, script, gatewayUrl: deps.gatewayUrl, npxCmd } };
|
|
27655
|
+
const npxCmd = buildNpxCmd({ gatewayUrl: deps.gatewayUrl, nodeId, token: enroll.token, nodeName });
|
|
27656
|
+
return { status: 200, body: { nodeId, nodeName, token: enroll.token, script, gatewayUrl: deps.gatewayUrl, npxCmd } };
|
|
27657
|
+
});
|
|
27658
|
+
router.post("/api/nodes/exchange", async (req) => {
|
|
27659
|
+
const body = req.body ?? {};
|
|
27660
|
+
const enrollToken = body.enrollToken?.trim();
|
|
27661
|
+
if (!enrollToken) return { status: 400, body: { error: "missing enrollToken" } };
|
|
27662
|
+
const consumed = deps.enrollTokens.consume(enrollToken);
|
|
27663
|
+
if (!consumed) return { status: 401, body: { error: "invalid or expired enroll token" } };
|
|
27664
|
+
const nodeId = body.nodeId?.trim() || consumed.nodeId;
|
|
27665
|
+
const existing = deps.nodeTokens.list().find((e) => e.nodeId === nodeId);
|
|
27666
|
+
const token = existing?.token ?? deps.nodeTokens.issue(nodeId);
|
|
27667
|
+
return { status: 200, body: { nodeId, token } };
|
|
27560
27668
|
});
|
|
27561
27669
|
router.patch("/api/nodes/:nodeId", async (req) => {
|
|
27562
27670
|
const nodeId = req.params["nodeId"];
|
|
@@ -27751,7 +27859,15 @@ function buildWorkorderDetail(model, workspaceId, resolveActor, resolveProject,
|
|
|
27751
27859
|
const activity = buildActivity(model, arts, ref);
|
|
27752
27860
|
const acceptance = buildAcceptance(model, arts);
|
|
27753
27861
|
const planning = planningStatusOf(model, arts);
|
|
27754
|
-
|
|
27862
|
+
const spec = workorderSpecOf(model, arts);
|
|
27863
|
+
return {
|
|
27864
|
+
summary,
|
|
27865
|
+
graph: { nodes, edges },
|
|
27866
|
+
activity,
|
|
27867
|
+
acceptance,
|
|
27868
|
+
...spec?.acceptanceCriteria ? { acceptanceCriteria: spec.acceptanceCriteria } : {},
|
|
27869
|
+
planning
|
|
27870
|
+
};
|
|
27755
27871
|
}
|
|
27756
27872
|
function buildRuntimeByArtifact(entries, ref) {
|
|
27757
27873
|
const byJob = /* @__PURE__ */ new Map();
|
|
@@ -29737,6 +29853,7 @@ var init_src4 = __esm({
|
|
|
29737
29853
|
init_sender();
|
|
29738
29854
|
init_routes4();
|
|
29739
29855
|
init_node_store();
|
|
29856
|
+
init_tokens();
|
|
29740
29857
|
init_collab();
|
|
29741
29858
|
init_trace2();
|
|
29742
29859
|
init_chat_sessions();
|
|
@@ -35236,7 +35353,9 @@ function buildClaudeUsage(acc) {
|
|
|
35236
35353
|
}
|
|
35237
35354
|
function scrubLeakyEnv(env) {
|
|
35238
35355
|
const LEAKY = /^npm_|^PNPM_|^INIT_CWD$|^OLDPWD$/;
|
|
35239
|
-
|
|
35356
|
+
const out = Object.fromEntries(Object.entries(env).filter(([k]) => !LEAKY.test(k)));
|
|
35357
|
+
if (out["ANTHROPIC_AUTH_TOKEN"]) delete out["ANTHROPIC_API_KEY"];
|
|
35358
|
+
return out;
|
|
35240
35359
|
}
|
|
35241
35360
|
function classifyExit(result) {
|
|
35242
35361
|
if (!result) return void 0;
|
|
@@ -38899,7 +39018,6 @@ async function buildActorProvision(service, actorId) {
|
|
|
38899
39018
|
if (raw["FEISHU_APP_ID"] && raw["FEISHU_APP_SECRET"]) {
|
|
38900
39019
|
try {
|
|
38901
39020
|
const feishu = new FeishuConnector();
|
|
38902
|
-
await feishu.connect({ app_id: raw["FEISHU_APP_ID"], app_secret: raw["FEISHU_APP_SECRET"] });
|
|
38903
39021
|
const sessionEnv = /* @__PURE__ */ new Map();
|
|
38904
39022
|
await feishu.inject({ app_id: raw["FEISHU_APP_ID"], app_secret: raw["FEISHU_APP_SECRET"] }, sessionEnv);
|
|
38905
39023
|
for (const [k, v] of sessionEnv) env[k] = v;
|
|
@@ -38992,6 +39110,7 @@ async function startServe(opts) {
|
|
|
38992
39110
|
const operatorToken = issuer.issue(operatorActor);
|
|
38993
39111
|
fs13.writeFileSync(path11.join(opts.dir, "operator-token"), operatorToken, { mode: 384 });
|
|
38994
39112
|
const nodeTokens = createNodeTokenStore(path11.join(opts.dir, "node-tokens.json"));
|
|
39113
|
+
const enrollTokens = createEnrollTokenStore();
|
|
38995
39114
|
const nodeStore = await FileNodeStore.open(path11.join(opts.dir, "nodes.json"));
|
|
38996
39115
|
const registryAuditFile = path11.join(opts.dir, "registry-audit.ndjson");
|
|
38997
39116
|
const registryListeners = /* @__PURE__ */ new Set();
|
|
@@ -39239,6 +39358,7 @@ async function startServe(opts) {
|
|
|
39239
39358
|
nodesDomain({
|
|
39240
39359
|
getHub: () => hub,
|
|
39241
39360
|
nodeTokens,
|
|
39361
|
+
enrollTokens,
|
|
39242
39362
|
nodeStore,
|
|
39243
39363
|
gatewayUrl: opts.gatewayUrl ?? `ws://127.0.0.1:${opts.port ?? 7320}/node-gateway`,
|
|
39244
39364
|
repoRemote: opts.nodeRepoRemote ?? "git@github.com:open-friday/oasis-core.git"
|
|
@@ -39980,7 +40100,7 @@ var USAGE = `oasis \u2014\u2014 artifact-centric \u534F\u4F5C\u5185\u6838 CLI\uF
|
|
|
39980
40100
|
accept <artifactId> [--note "\u2026"] # \u5B9A\u7A3F\uFF08\u5148 conclude \u518D accept\uFF09
|
|
39981
40101
|
assign <artifactId> --owner <actorId>
|
|
39982
40102
|
gc # \u5B64\u513F blob \u56DE\u6536\uFF08mark-and-sweep\uFF1B\u64CD\u4F5C\u8005\u547D\u4EE4\uFF0CF1\uFF09
|
|
39983
|
-
\u8BFB\u4EA7\u7269: status <id>\uFF08\u72B6\u6001\u7D22\u5F15\uFF0C\u4E0D\u542B\u6B63\u6587\uFF09/ content <id> [path]\uFF08\u5B9E\u9645\u5185\u5BB9\uFF0C\u591A\u6587\u4EF6\u7ED9 path \u53D6\u5355\u4E2A\uFF09/ project <id>\uFF08\u9879\u76EE\u76EE\u5F55\uFF09 # \u7ED9 agent\uFF0C\u6E10\u8FDB\u62AB\u9732
|
|
40103
|
+
\u8BFB\u4EA7\u7269: status <id>\uFF08\u72B6\u6001\u7D22\u5F15\uFF0C\u4E0D\u542B\u6B63\u6587\uFF09/ content <id> [path]\uFF08\u5B9E\u9645\u5185\u5BB9\uFF0C\u591A\u6587\u4EF6\u7ED9 path \u53D6\u5355\u4E2A\uFF09/ projects [--search q]\uFF08\u5217/\u641C\u9879\u76EE\uFF09/ project <id>\uFF08\u9879\u76EE\u76EE\u5F55\uFF09 # \u7ED9 agent\uFF0C\u6E10\u8FDB\u62AB\u9732
|
|
39984
40104
|
graph / show / log / ls # \u5168\u5C40/\u8BE6\u5C3D\u89C6\u56FE\uFF08\u534F\u8C03\u8005\u3001\u4EBA\uFF1Bls \u4EC5\u534F\u8C03\u8005\uFF09
|
|
39985
40105
|
|
|
39986
40106
|
\u6CBB\u7406\uFF08\xA711\uFF09
|
|
@@ -40370,6 +40490,16 @@ async function runCli(argv, println = console.log) {
|
|
|
40370
40490
|
return;
|
|
40371
40491
|
}
|
|
40372
40492
|
switch (command) {
|
|
40493
|
+
case "projects": {
|
|
40494
|
+
const res = await api.request("GET", "/api/projects");
|
|
40495
|
+
const q = flags.get("search")?.trim().toLowerCase();
|
|
40496
|
+
const items = q ? res.items.filter((p) => `${p.project_id} ${p.name} ${p.description ?? ""}`.toLowerCase().includes(q)) : res.items;
|
|
40497
|
+
println(`\u9879\u76EE(${items.length}${q ? ` / \u641C\u300C${q}\u300D` : ""})\u2014\u2014\u8BE6\u60C5\u7528 \`oasis project <id>\`\u3001\u6CA1\u5408\u9002\u7684\u53EF \`oasis project create\`:`);
|
|
40498
|
+
for (const p of items) println(`- ${p.project_id} ${p.name}${p.description ? ` \u76EE\u6807: ${p.description}` : ""}`);
|
|
40499
|
+
if (items.length === 0) println("\uFF08\u65E0\u5339\u914D\u2014\u2014\u53EF project create \u65B0\u5EFA\uFF0C\u6216\u5411\u7528\u6237\u6F84\u6E05\uFF09");
|
|
40500
|
+
if (res.next_cursor) println("\uFF08\u8FD8\u6709\u66F4\u591A\u9879\u76EE\u672A\u5217\u5168\uFF0C\u7528 --search \u7F29\u5C0F\u8303\u56F4\uFF09");
|
|
40501
|
+
break;
|
|
40502
|
+
}
|
|
40373
40503
|
case "project": {
|
|
40374
40504
|
const projSub = positional[0];
|
|
40375
40505
|
if (projSub && !["create", "docs", "progress", "run-state"].includes(projSub)) {
|
|
@@ -41130,12 +41260,27 @@ void (async () => {
|
|
|
41130
41260
|
if (cmd === "start") {
|
|
41131
41261
|
const prev = readConfig();
|
|
41132
41262
|
const serverUrl = flags.get("server-ws") ?? process.env["OASIS_SERVER_WS"] ?? prev?.serverUrl;
|
|
41133
|
-
|
|
41134
|
-
|
|
41135
|
-
console.error("Usage: oasis start --server-ws <wss://...> --token <token> [--name <name>] [--id <nodeId>]");
|
|
41263
|
+
if (!serverUrl) {
|
|
41264
|
+
console.error("Usage: oasis start --server-ws <wss://...> (--enroll-token <ent_...> | --token <ont_...>) [--name <name>] [--id <nodeId>]");
|
|
41136
41265
|
process.exit(1);
|
|
41137
41266
|
}
|
|
41138
41267
|
const nodeId = prev?.nodeId ?? flags.get("id") ?? `node-${(0, import_node_crypto21.randomUUID)()}`;
|
|
41268
|
+
let token = flags.get("token") ?? process.env["OASIS_NODE_TOKEN"] ?? prev?.token;
|
|
41269
|
+
const enrollToken = flags.get("enroll-token") ?? process.env["OASIS_ENROLL_TOKEN"];
|
|
41270
|
+
if (enrollToken) {
|
|
41271
|
+
const res = await fetch(`${httpBase(serverUrl)}/api/nodes/exchange`, {
|
|
41272
|
+
method: "POST",
|
|
41273
|
+
headers: { "content-type": "application/json" },
|
|
41274
|
+
body: JSON.stringify({ enrollToken, nodeId })
|
|
41275
|
+
});
|
|
41276
|
+
if (!res.ok) throw new Error(`enroll token exchange failed: HTTP ${res.status}`);
|
|
41277
|
+
const body = await res.json();
|
|
41278
|
+
token = body.token;
|
|
41279
|
+
}
|
|
41280
|
+
if (!token) {
|
|
41281
|
+
console.error("Usage: oasis start --server-ws <wss://...> (--enroll-token <ent_...> | --token <ont_...>) [--name <name>] [--id <nodeId>]");
|
|
41282
|
+
process.exit(1);
|
|
41283
|
+
}
|
|
41139
41284
|
const name = flags.get("name") ?? prev?.name;
|
|
41140
41285
|
const nameChanged = prev?.name !== void 0 && name !== prev.name;
|
|
41141
41286
|
saveConfig({ serverUrl, token, nodeId, ...name ? { name } : {} });
|