@wowok/agent-mcp 2.5.5 → 2.6.0

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.
Files changed (38) hide show
  1. package/dist/config/runtime.js +3 -6
  2. package/dist/harness/checkpoint.js +2 -2
  3. package/dist/knowledge/flywheel-loop.js +2 -5
  4. package/dist/knowledge/overrides-loader.js +2 -4
  5. package/dist/knowledge/progress-ledger.js +3 -0
  6. package/dist/knowledge/progress-translation.js +5 -1
  7. package/dist/loop-engineering/improve.js +2 -4
  8. package/dist/project/deployment-bridge.d.ts +5 -0
  9. package/dist/project/deployment-bridge.js +96 -0
  10. package/dist/project/evaluation.js +10 -3
  11. package/dist/project/graph-builder.js +15 -2
  12. package/dist/project/handlers.d.ts +2 -0
  13. package/dist/project/handlers.js +115 -6
  14. package/dist/project/index.js +2 -6
  15. package/dist/project/project-store.js +2 -5
  16. package/dist/schema/config/index.d.ts +12 -12
  17. package/dist/schema/local/index.d.ts +108 -108
  18. package/dist/schema/local/index.js +21 -18
  19. package/dist/schema/messenger/index.d.ts +16 -16
  20. package/dist/schema/messenger/index.js +2 -2
  21. package/dist/schema/operations.d.ts +0 -6
  22. package/dist/schema/project/index.d.ts +271 -7
  23. package/dist/schema/project/index.js +52 -0
  24. package/dist/schema/query/index.d.ts +10 -5
  25. package/dist/schema/trust/index.d.ts +8 -8
  26. package/dist/schemas/account_operation.output.json +7 -21
  27. package/dist/schemas/account_operation.schema.json +9 -23
  28. package/dist/schemas/index.json +1 -1
  29. package/dist/schemas/messenger_operation.schema.json +6 -6
  30. package/dist/schemas/project_operation.output.json +180 -0
  31. package/dist/schemas/project_operation.schema.json +14 -1
  32. package/dist/schemas/query_toolkit.output.json +7 -6
  33. package/dist/schemas/query_toolkit.schema.json +0 -4
  34. package/dist/telemetry/storage.js +2 -2
  35. package/dist/tools/handlers/onchain.js +13 -0
  36. package/dist/tools/handlers/project.js +22 -0
  37. package/dist/tools/index.js +1 -1
  38. package/package.json +2 -2
@@ -1,6 +1,6 @@
1
1
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
2
2
  import { dirname, join } from "path";
3
- import { homedir } from "os";
3
+ import { getWowMcpDir } from "@wowok/wowok";
4
4
  export const SERVICE_REGISTRY = [
5
5
  {
6
6
  name: "confirm_gate",
@@ -70,10 +70,7 @@ const SERVICE_MAP = new Map(SERVICE_REGISTRY.map((s) => [s.name, s]));
70
70
  const runtimeOverrides = new Map();
71
71
  let harnessTierOverride;
72
72
  function configFilePath() {
73
- const dir = process.env.WOWOK_CONFIG_DIR
74
- ? process.env.WOWOK_CONFIG_DIR
75
- : join(homedir(), ".wowok");
76
- return join(dir, "runtime-config.json");
73
+ return join(getWowMcpDir(), "runtime-config.json");
77
74
  }
78
75
  function isPersistEnabled() {
79
76
  const v = process.env.WOWOK_RUNTIME_CONFIG_PERSIST;
@@ -220,7 +217,7 @@ function buildReminder(service, enabled) {
220
217
  : "Harness is OFF. GLM5 recommends keeping it ON (lightweight tier) for safety. To enable, call config_operation toggle harness.";
221
218
  case "graph_persist":
222
219
  return enabled
223
- ? "Graph persistence is ON: the object dependency graph will be saved to ~/.wowok/project-graph.json."
220
+ ? "Graph persistence is ON: the object dependency graph will be saved to ~/.wow/mcp/project-graph.json."
224
221
  : "Graph persistence is OFF: the dependency graph exists only in memory and will be lost on process restart. To persist, call config_operation toggle graph_persist.";
225
222
  case "semantic_rich":
226
223
  return undefined;
@@ -1,7 +1,7 @@
1
1
  import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync, unlinkSync, openSync, closeSync } from "fs";
2
2
  import { join } from "path";
3
- import { homedir } from "os";
4
- const CHECKPOINT_ROOT = join(homedir(), ".wowok", "checkpoints");
3
+ import { getWowMcpDir } from "@wowok/wowok";
4
+ const CHECKPOINT_ROOT = join(getWowMcpDir(), "checkpoints");
5
5
  function getTaskDir(taskId) {
6
6
  return join(CHECKPOINT_ROOT, taskId);
7
7
  }
@@ -3,7 +3,7 @@ import { getIndustryProfile, resolveIndustryName } from "./industry-registry.js"
3
3
  import { evaluateIndustryHealthByIntent, suggestIndustryUpdateByIntent, getRoleAdvice, filterSuggestionsByRole, getIntentProfile, } from "./intent-metrics.js";
4
4
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
5
5
  import { dirname, join } from "path";
6
- import { homedir } from "os";
6
+ import { getWowMcpDir } from "@wowok/wowok";
7
7
  export const FLYWHEEL_LOOP_VERSION = 2;
8
8
  const MIN_SIGNALS_FOR_EVOLUTION = 10;
9
9
  const DEFAULT_SCHEDULE = {
@@ -287,10 +287,7 @@ export function getIndustryEvolutionStatus(industry) {
287
287
  }
288
288
  export const EVOLUTION_STATE_VERSION = 1;
289
289
  function evolutionStateFilePath() {
290
- const dir = process.env.WOWOK_CONFIG_DIR
291
- ? process.env.WOWOK_CONFIG_DIR
292
- : join(homedir(), ".wowok");
293
- return join(dir, "evolution-state.json");
290
+ return join(getWowMcpDir(), "evolution-state.json");
294
291
  }
295
292
  export function saveEvolutionState() {
296
293
  const path = evolutionStateFilePath();
@@ -1,10 +1,8 @@
1
1
  import { readFileSync, existsSync, readdirSync } from "fs";
2
2
  import { join } from "path";
3
- import { homedir } from "os";
3
+ import { getWowMcpDir } from "@wowok/wowok";
4
4
  function wowokRootDir() {
5
- return process.env.WOWOK_CONFIG_DIR
6
- ? process.env.WOWOK_CONFIG_DIR
7
- : join(homedir(), ".wowok");
5
+ return getWowMcpDir();
8
6
  }
9
7
  function overridesDir() {
10
8
  return join(wowokRootDir(), "overrides");
@@ -219,6 +219,9 @@ export const PROGRESS_SCENES = [
219
219
  "Progress.current = next_node only after session completes (atomic update)",
220
220
  "E_NOT_THE_HOLDER: if forward was held by another address, next() aborts",
221
221
  "E_FORWARD_ALREADY_ACCOMPLISHED: re-hold on completed forward is blocked",
222
+ "⚠ ROUTING RULE: Forward.namedOperator=\"\" (empty) → MUST call order.progress (order_next); " +
223
+ "non-empty namedOperator or permissionIndex-only → MUST call progress.operate (next). " +
224
+ "Wrong path → Permission denied (abort code 5). See file header CRITICAL ROUTING RULE.",
222
225
  ],
223
226
  recommended_templates: ["T-PR-04"],
224
227
  },
@@ -15,7 +15,11 @@ export const PROGRESS_SEMANTIC_TO_SCHEMA_RULES = [
15
15
  },
16
16
  },
17
17
  reverse_explanation: "operate.op='next' → calls progress::next or order_next (if task bound). " +
18
- "Move accumulates forward.weight; on reaching threshold, session → history and current = next_node_name.",
18
+ "Move accumulates forward.weight; on reaching threshold, session → history and current = next_node_name. " +
19
+ "⚠ ROUTING RULE: When Forward.namedOperator=\"\" (empty string = OrderHolder), the caller MUST use " +
20
+ "order.progress (not progress.operate) — order_next uses order.has_op_permission which recognizes " +
21
+ "the OrderHolder short-circuit. Direct progress::next will abort with 'Permission denied' (code 5). " +
22
+ "For non-empty namedOperator or permissionIndex-only forwards, use progress.operate directly.",
19
23
  },
20
24
  {
21
25
  id: "P-PR-02",
@@ -1,7 +1,7 @@
1
1
  import { getPendingSuggestions } from "../knowledge/flywheel-loop.js";
2
2
  import { readFileSync, writeFileSync, existsSync, mkdirSync, appendFileSync, readdirSync } from "fs";
3
3
  import { join, dirname } from "path";
4
- import { homedir } from "os";
4
+ import { getWowMcpDir } from "@wowok/wowok";
5
5
  function proposeErrorRuleAddition(diagnosis) {
6
6
  const evidence = diagnosis.evidence;
7
7
  const topMessages = evidence.top_error_messages || [];
@@ -245,9 +245,7 @@ export function generateImprovements(report) {
245
245
  };
246
246
  }
247
247
  function wowokRootDir() {
248
- return process.env.WOWOK_CONFIG_DIR
249
- ? process.env.WOWOK_CONFIG_DIR
250
- : join(homedir(), ".wowok");
248
+ return getWowMcpDir();
251
249
  }
252
250
  function improvementQueuePath() {
253
251
  return join(wowokRootDir(), "improvement-queue.jsonl");
@@ -0,0 +1,5 @@
1
+ import type { DeploymentDocValidationResult } from "./deployment-doc.js";
2
+ export declare function generateDeploymentDocFromProject(projectId: string, network: "testnet" | "mainnet"): Promise<{
3
+ markdown: string;
4
+ validation: DeploymentDocValidationResult;
5
+ }>;
@@ -0,0 +1,96 @@
1
+ import { LocalProject } from "@wowok/wowok";
2
+ import { generateDeploymentDoc, validateDeploymentDoc } from "./deployment-doc.js";
3
+ export async function generateDeploymentDocFromProject(projectId, network) {
4
+ const project = await LocalProject.Instance().getProject(projectId);
5
+ if (!project) {
6
+ throw new Error(`Project not found: ${projectId}`);
7
+ }
8
+ const objects = await LocalProject.Instance().listObjects(projectId);
9
+ const graphEdges = await LocalProject.Instance().getGraph(projectId);
10
+ const evaluations = await LocalProject.Instance().listEvaluations(projectId, { evalType: "risk" });
11
+ const validObjects = objects.filter((o) => o.objectType !== null && o.objectType !== undefined);
12
+ const deployObjects = validObjects.map((o) => {
13
+ const objectType = o.objectType;
14
+ return {
15
+ entry_id: `${objectType}:${o.objectName || o.objectAddress || o.id}`,
16
+ object_type: normalizeObjectType(objectType),
17
+ name: o.objectName || o.objectAddress || o.id,
18
+ reused_from: o.objectAddress.startsWith("0x") ? o.objectAddress : undefined,
19
+ publish_required: objectType === "service" || objectType === "machine",
20
+ };
21
+ });
22
+ const addrToEntryId = new Map();
23
+ for (const o of validObjects) {
24
+ const objectType = o.objectType;
25
+ const entryId = `${objectType}:${o.objectName || o.objectAddress || o.id}`;
26
+ if (o.objectAddress) {
27
+ addrToEntryId.set(o.objectAddress, entryId);
28
+ }
29
+ if (o.objectName) {
30
+ addrToEntryId.set(o.objectName, entryId);
31
+ }
32
+ }
33
+ const deployEdges = graphEdges.map((e) => ({
34
+ from: addrToEntryId.get(e.sourceObject) ?? e.sourceObject,
35
+ to: addrToEntryId.get(e.targetObject) ?? e.targetObject,
36
+ edge_kind: e.relationshipType,
37
+ field_path: e.fieldName || "",
38
+ required_at_publish: e.edgeSource === "internal",
39
+ }));
40
+ const steps = buildTopoSteps(deployObjects, deployEdges, network);
41
+ const riskEval = evaluations[0];
42
+ const risk_status = riskEval
43
+ ? (riskEval.score !== null && riskEval.score < 50 ? "RISK_BLOCKED" : "RISK_PASSED")
44
+ : undefined;
45
+ const riskDetails = riskEval?.details;
46
+ const risk_critical_count = riskDetails?.critical_count;
47
+ const risk_high_count = riskDetails?.high_count;
48
+ const input = {
49
+ project_prefix: project.prefix,
50
+ business_intent: project.description || project.name,
51
+ industry: project.industry || "general",
52
+ version: project.currentVersion || "v1",
53
+ objects: deployObjects,
54
+ edges: deployEdges,
55
+ steps,
56
+ risk_status,
57
+ risk_critical_count,
58
+ risk_high_count,
59
+ };
60
+ const markdown = generateDeploymentDoc(input);
61
+ const validation = validateDeploymentDoc(input);
62
+ return { markdown, validation };
63
+ }
64
+ function normalizeObjectType(raw) {
65
+ const lower = raw.toLowerCase();
66
+ if (lower === "arbitration")
67
+ return "arb";
68
+ return lower;
69
+ }
70
+ function buildTopoSteps(objects, edges, network) {
71
+ const typeOrder = {
72
+ permission: 1, treasury: 2, allocation: 3, guard: 4,
73
+ service: 10, machine: 11, progress: 12,
74
+ order: 20, arb: 22,
75
+ reward: 30, proof: 32,
76
+ repository: 40, demand: 41, contact: 42,
77
+ personal: 51, payment: 52,
78
+ };
79
+ const sorted = [...objects].sort((a, b) => {
80
+ const oa = typeOrder[a.object_type] ?? 99;
81
+ const ob = typeOrder[b.object_type] ?? 99;
82
+ return oa - ob;
83
+ });
84
+ return sorted.map((obj, i) => ({
85
+ step: i + 1,
86
+ object_type: obj.object_type,
87
+ operation: obj.publish_required ? "publish" : "create",
88
+ substep_count: 1,
89
+ depends_on: edges
90
+ .filter((e) => e.to === obj.entry_id)
91
+ .map((e) => sorted.findIndex((o) => o.entry_id === e.from) + 1)
92
+ .filter((n) => n > 0),
93
+ entry_id: obj.entry_id,
94
+ network_phase: network,
95
+ }));
96
+ }
@@ -39,6 +39,13 @@ const CONSUMER_DUE_DILIGENCE = [
39
39
  function clampScore(n) {
40
40
  return Math.max(0, Math.min(100, Math.round(n)));
41
41
  }
42
+ function shortTypeName(objectType) {
43
+ if (!objectType)
44
+ return "unknown";
45
+ const base = objectType.replace(/<.*>/, "").trim();
46
+ const segments = base.split("::");
47
+ return segments[segments.length - 1] || "unknown";
48
+ }
42
49
  function parseCacheData(cached) {
43
50
  if (!cached)
44
51
  return null;
@@ -146,7 +153,7 @@ function evaluateRisk(input) {
146
153
  const { objects, edges, objectCache, project } = input;
147
154
  const byType = new Map();
148
155
  for (const obj of objects) {
149
- const t = obj.objectType ?? "unknown";
156
+ const t = shortTypeName(obj.objectType);
150
157
  if (!byType.has(t))
151
158
  byType.set(t, []);
152
159
  byType.get(t).push(obj);
@@ -340,7 +347,7 @@ function evaluateTrust(input) {
340
347
  const { objects, edges, objectCache, reputation, project } = input;
341
348
  const byType = new Map();
342
349
  for (const obj of objects) {
343
- const t = obj.objectType ?? "unknown";
350
+ const t = shortTypeName(obj.objectType);
344
351
  if (!byType.has(t))
345
352
  byType.set(t, []);
346
353
  byType.get(t).push(obj);
@@ -578,7 +585,7 @@ function evaluateCompleteness(input) {
578
585
  const { objects, edges, objectCache, project } = input;
579
586
  const byType = new Map();
580
587
  for (const obj of objects) {
581
- const t = obj.objectType ?? "unknown";
588
+ const t = shortTypeName(obj.objectType);
582
589
  if (!byType.has(t))
583
590
  byType.set(t, []);
584
591
  byType.get(t).push(obj);
@@ -1,5 +1,12 @@
1
1
  import { query_objects, queryTableItem_EntityLinker, LocalProject, } from "@wowok/wowok";
2
2
  const MAX_OBJECTS_PER_QUERY = 50;
3
+ function shortTypeName(objectType) {
4
+ if (!objectType)
5
+ return "unknown";
6
+ const base = objectType.replace(/<.*>/, "").trim();
7
+ const segments = base.split("::");
8
+ return segments[segments.length - 1] || "unknown";
9
+ }
3
10
  function extractAddressFields(obj) {
4
11
  const refs = [];
5
12
  const objType = obj.type;
@@ -35,6 +42,8 @@ function extractAddressFields(obj) {
35
42
  for (const alloc of data.order_allocators.allocators) {
36
43
  addRef(alloc.guard, "allocator_guard", "validate");
37
44
  }
45
+ const firstGuard = data.order_allocators.allocators[0]?.guard;
46
+ addRef(firstGuard, "order_allocators", "create");
38
47
  }
39
48
  addRefOption(data.compensation_fund, "compensation_fund", "bind");
40
49
  break;
@@ -449,7 +458,7 @@ export class GraphBuilder {
449
458
  }
450
459
  const byType = new Map();
451
460
  for (const obj of projectObjects) {
452
- const type = obj.objectType ?? "unknown";
461
+ const type = shortTypeName(obj.objectType);
453
462
  if (!byType.has(type))
454
463
  byType.set(type, []);
455
464
  byType.get(type).push({
@@ -504,6 +513,8 @@ export class GraphBuilder {
504
513
  resolveConflicts(edges) {
505
514
  const edgeMap = new Map();
506
515
  for (const edge of edges) {
516
+ if (!edge.sourceObject || !edge.targetObject)
517
+ continue;
507
518
  const key = `${edge.sourceObject}→${edge.targetObject}:${edge.relationshipType}`;
508
519
  const list = edgeMap.get(key) ?? [];
509
520
  list.push(edge);
@@ -541,10 +552,12 @@ export class GraphBuilder {
541
552
  const ensureNode = (addr) => {
542
553
  if (!nodeMap.has(addr)) {
543
554
  const obj = objectCache.get(addr);
555
+ const queryName = obj?.query_name;
556
+ const objectName = queryName && queryName !== addr ? queryName : null;
544
557
  nodeMap.set(addr, {
545
558
  address: addr,
546
559
  objectType: obj?.type ?? null,
547
- objectName: null,
560
+ objectName,
548
561
  role: null,
549
562
  isCore: addr === rootAddress,
550
563
  });
@@ -6,6 +6,7 @@ export declare function handleListProjects(v: ProjectInput): Promise<{
6
6
  action: "list_projects";
7
7
  items: {
8
8
  objectCount: number;
9
+ evaluationCount: number;
9
10
  objectTypes: string[];
10
11
  id: string;
11
12
  prefix: string;
@@ -49,6 +50,7 @@ export declare function handleGetProjectDetail(v: ProjectInput): Promise<{
49
50
  evalType: EvaluationType;
50
51
  score: number | null;
51
52
  summary: string | null;
53
+ details: Record<string, unknown> | null;
52
54
  evaluatedAt: number;
53
55
  }[];
54
56
  versions: {
@@ -41,15 +41,30 @@ export async function handleListProjects(v) {
41
41
  filter.network = v.filter_network;
42
42
  const projects = await localProject.listProjects(Object.keys(filter).length > 0 ? filter : undefined);
43
43
  const items = await Promise.all(projects.map(async (p) => {
44
- const objs = await localProject.listObjects(p.id);
44
+ const [objs, evals] = await Promise.all([
45
+ localProject.listObjects(p.id),
46
+ localProject.listEvaluations(p.id),
47
+ ]);
45
48
  const types = new Set();
46
49
  for (const o of objs) {
47
50
  if (o.objectType)
48
51
  types.add(o.objectType);
49
52
  }
53
+ if (p.status === "draft" && objs.length > 0) {
54
+ const updated = await localProject.updateProject(p.id, { status: "active" });
55
+ if (updated) {
56
+ return {
57
+ ...updated,
58
+ objectCount: objs.length,
59
+ evaluationCount: evals.length,
60
+ objectTypes: Array.from(types),
61
+ };
62
+ }
63
+ }
50
64
  return {
51
65
  ...p,
52
66
  objectCount: objs.length,
67
+ evaluationCount: evals.length,
53
68
  objectTypes: Array.from(types),
54
69
  };
55
70
  }));
@@ -126,9 +141,10 @@ export async function handleCreateProjectFromOnchain(v) {
126
141
  });
127
142
  objects.push(obj);
128
143
  }
144
+ const updatedProject = await localProject.updateProject(project.id, { status: "active" });
129
145
  return {
130
146
  action: "create_project_from_onchain",
131
- project,
147
+ project: updatedProject ?? project,
132
148
  objects,
133
149
  graphEdgeCount: graphResult.graph.edges.length,
134
150
  };
@@ -156,9 +172,66 @@ export async function handleGetProjectDetail(v) {
156
172
  const edges = await localProject.getGraph(id);
157
173
  const evaluations = await localProject.listEvaluations(id);
158
174
  const versions = await localProject.listVersions(id);
175
+ let effectiveProject = project;
176
+ if (project.status === "draft" && objects.length > 0) {
177
+ const updated = await localProject.updateProject(id, { status: "active" });
178
+ if (updated)
179
+ effectiveProject = updated;
180
+ }
181
+ const needsNameFix = objects.some(o => !o.objectName);
182
+ const needsRoleFix = objects.some(o => o.role === "reference");
183
+ if (needsNameFix || needsRoleFix) {
184
+ const allMarks = await LocalMark.Instance().list(null);
185
+ const addressToName = new Map();
186
+ for (const m of allMarks) {
187
+ if (m.name && m.address) {
188
+ addressToName.set(m.address.toLowerCase(), m.name);
189
+ }
190
+ }
191
+ for (const obj of objects) {
192
+ const updates = {};
193
+ if (!obj.objectName) {
194
+ const name = addressToName.get(obj.objectAddress.toLowerCase());
195
+ if (name) {
196
+ updates.objectName = name;
197
+ obj.objectName = name;
198
+ }
199
+ }
200
+ if (obj.role === "reference" && obj.objectType) {
201
+ const t = obj.objectType;
202
+ if (t.includes("service::Service")) {
203
+ updates.role = "core";
204
+ obj.role = "core";
205
+ }
206
+ else if (t.includes("permission::Permission") ||
207
+ t.includes("machine::Machine") ||
208
+ t.includes("guard::Guard") ||
209
+ t.includes("reward::Reward") ||
210
+ t.includes("treasury::Treasury") ||
211
+ t.includes("allocation::Allocation") ||
212
+ t.includes("progress::Progress") ||
213
+ t.includes("arbitration::Arbitration") ||
214
+ t.includes("demand::Demand") ||
215
+ t.includes("order::Order") ||
216
+ t.includes("repository::Repository")) {
217
+ updates.role = "dependency";
218
+ obj.role = "dependency";
219
+ }
220
+ }
221
+ if (effectiveProject.serviceAddress &&
222
+ obj.objectAddress === effectiveProject.serviceAddress &&
223
+ obj.role !== "core") {
224
+ updates.role = "core";
225
+ obj.role = "core";
226
+ }
227
+ if (Object.keys(updates).length > 0) {
228
+ await localProject.updateObject(obj.id, updates).catch(() => { });
229
+ }
230
+ }
231
+ }
159
232
  return {
160
233
  action: "get_project_detail",
161
- project,
234
+ project: effectiveProject,
162
235
  objects,
163
236
  graphEdgeCount: edges.length,
164
237
  evaluations: evaluations.map(e => ({
@@ -166,6 +239,7 @@ export async function handleGetProjectDetail(v) {
166
239
  evalType: e.evalType,
167
240
  score: e.score,
168
241
  summary: e.summary,
242
+ details: e.details,
169
243
  evaluatedAt: e.evaluatedAt,
170
244
  })),
171
245
  versions: versions.map(v => ({
@@ -178,13 +252,47 @@ export async function handleGetProjectDetail(v) {
178
252
  export async function handleAddObject(v) {
179
253
  const projectId = await resolveProjectId(v);
180
254
  const objectAddress = await resolveObjectAddress(v);
255
+ let objectName = v.object_name_add;
256
+ let role = v.object_role;
257
+ if (!objectName) {
258
+ const marks = await LocalMark.Instance().list({ address: objectAddress });
259
+ if (marks.length > 0 && marks[0].name) {
260
+ objectName = marks[0].name;
261
+ }
262
+ }
263
+ if (!role) {
264
+ const objType = v.object_type_add ?? "";
265
+ if (objType.includes("service::Service")) {
266
+ role = "core";
267
+ }
268
+ else if (objType.includes("::") && (objType.includes("permission::") ||
269
+ objType.includes("machine::") ||
270
+ objType.includes("guard::") ||
271
+ objType.includes("reward::") ||
272
+ objType.includes("treasury::") ||
273
+ objType.includes("allocation::") ||
274
+ objType.includes("progress::") ||
275
+ objType.includes("arbitration::") ||
276
+ objType.includes("demand::") ||
277
+ objType.includes("order::") ||
278
+ objType.includes("repository::"))) {
279
+ role = "dependency";
280
+ }
281
+ else {
282
+ role = "reference";
283
+ }
284
+ }
181
285
  const obj = await localProject.addObject(projectId, {
182
286
  objectAddress,
183
287
  objectType: v.object_type_add,
184
- objectName: v.object_name_add,
185
- role: v.object_role ?? "reference",
288
+ objectName,
289
+ role,
186
290
  tags: v.object_tags_add,
187
291
  });
292
+ const project = await localProject.getProject(projectId);
293
+ if (project && project.status === "draft") {
294
+ await localProject.updateProject(projectId, { status: "active" });
295
+ }
188
296
  return { action: "add_object", object: obj };
189
297
  }
190
298
  export async function handleRemoveObject(v) {
@@ -233,7 +341,8 @@ export async function handleBuildGraph(v) {
233
341
  if (objects.length === 0) {
234
342
  throw new Error("Cannot build graph: project has no objects and no service_address");
235
343
  }
236
- rootAddress = objects[0].objectAddress;
344
+ const coreObj = objects.find(o => o.role === "core");
345
+ rootAddress = (coreObj ?? objects[0]).objectAddress;
237
346
  }
238
347
  const builder = new GraphBuilder({
239
348
  maxDepth: v.max_depth ?? 3,
@@ -2,10 +2,9 @@ import { normalizeForProject, extractProjectPrefix, extractAllProjectVersions, T
2
2
  import { ProjectGraph, extractReferences, nodeIdOf, } from "./graph.js";
3
3
  import { listProjects, listProjectObjects, listShareableObjects, traceDependencies, traceReferencedBy, prePublishCheck, findCrossProjectReferences, } from "./query.js";
4
4
  import { isEnabled as isRuntimeEnabled } from "../config/index.js";
5
- import { LocalMark } from "@wowok/wowok";
5
+ import { LocalMark, getWowMcpDir } from "@wowok/wowok";
6
6
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
7
7
  import { dirname, join } from "path";
8
- import { homedir } from "os";
9
8
  import * as ProjectStore from "./project-store.js";
10
9
  export * from "./namespace.js";
11
10
  export * from "./graph.js";
@@ -270,10 +269,7 @@ export function queryGraphStats() {
270
269
  };
271
270
  }
272
271
  function graphFilePath() {
273
- const dir = process.env.WOWOK_CONFIG_DIR
274
- ? process.env.WOWOK_CONFIG_DIR
275
- : join(homedir(), ".wowok");
276
- return join(dir, "project-graph.json");
272
+ return join(getWowMcpDir(), "project-graph.json");
277
273
  }
278
274
  export function saveGraph() {
279
275
  const path = graphFilePath();
@@ -1,12 +1,9 @@
1
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync, copyFileSync, statSync, appendFileSync, } from "fs";
2
2
  import { dirname, join } from "path";
3
- import { homedir } from "os";
3
+ import { getWowMcpDir } from "@wowok/wowok";
4
4
  export const CURRENT_SCHEMA_VERSION = "1.0.0";
5
5
  export function projectsRootDir() {
6
- const base = process.env.WOWOK_CONFIG_DIR
7
- ? process.env.WOWOK_CONFIG_DIR
8
- : join(homedir(), ".wowok");
9
- return join(base, "projects");
6
+ return join(getWowMcpDir(), "projects");
10
7
  }
11
8
  export function projectDir(prefix, version) {
12
9
  return join(projectsRootDir(), `${prefix}_${version}`);
@@ -46,13 +46,13 @@ export declare const ConfigOperationOutputSchema: z.ZodObject<{
46
46
  reminder: z.ZodOptional<z.ZodString>;
47
47
  }, "strip", z.ZodTypeAny, {
48
48
  action: "toggle";
49
- service: string;
50
49
  enabled: boolean;
50
+ service: string;
51
51
  reminder?: string | undefined;
52
52
  }, {
53
53
  action: "toggle";
54
- service: string;
55
54
  enabled: boolean;
55
+ service: string;
56
56
  reminder?: string | undefined;
57
57
  }>, z.ZodObject<{
58
58
  action: z.ZodLiteral<"enable">;
@@ -61,13 +61,13 @@ export declare const ConfigOperationOutputSchema: z.ZodObject<{
61
61
  reminder: z.ZodOptional<z.ZodString>;
62
62
  }, "strip", z.ZodTypeAny, {
63
63
  action: "enable";
64
- service: string;
65
64
  enabled: boolean;
65
+ service: string;
66
66
  reminder?: string | undefined;
67
67
  }, {
68
68
  action: "enable";
69
- service: string;
70
69
  enabled: boolean;
70
+ service: string;
71
71
  reminder?: string | undefined;
72
72
  }>, z.ZodObject<{
73
73
  action: z.ZodLiteral<"disable">;
@@ -76,13 +76,13 @@ export declare const ConfigOperationOutputSchema: z.ZodObject<{
76
76
  reminder: z.ZodOptional<z.ZodString>;
77
77
  }, "strip", z.ZodTypeAny, {
78
78
  action: "disable";
79
- service: string;
80
79
  enabled: boolean;
80
+ service: string;
81
81
  reminder?: string | undefined;
82
82
  }, {
83
83
  action: "disable";
84
- service: string;
85
84
  enabled: boolean;
85
+ service: string;
86
86
  reminder?: string | undefined;
87
87
  }>, z.ZodObject<{
88
88
  action: z.ZodLiteral<"reset">;
@@ -128,18 +128,18 @@ export declare const ConfigOperationOutputSchema: z.ZodObject<{
128
128
  }[];
129
129
  } | {
130
130
  action: "toggle";
131
- service: string;
132
131
  enabled: boolean;
132
+ service: string;
133
133
  reminder?: string | undefined;
134
134
  } | {
135
135
  action: "enable";
136
- service: string;
137
136
  enabled: boolean;
137
+ service: string;
138
138
  reminder?: string | undefined;
139
139
  } | {
140
140
  action: "disable";
141
- service: string;
142
141
  enabled: boolean;
142
+ service: string;
143
143
  reminder?: string | undefined;
144
144
  } | {
145
145
  action: "reset";
@@ -163,18 +163,18 @@ export declare const ConfigOperationOutputSchema: z.ZodObject<{
163
163
  }[];
164
164
  } | {
165
165
  action: "toggle";
166
- service: string;
167
166
  enabled: boolean;
167
+ service: string;
168
168
  reminder?: string | undefined;
169
169
  } | {
170
170
  action: "enable";
171
- service: string;
172
171
  enabled: boolean;
172
+ service: string;
173
173
  reminder?: string | undefined;
174
174
  } | {
175
175
  action: "disable";
176
- service: string;
177
176
  enabled: boolean;
177
+ service: string;
178
178
  reminder?: string | undefined;
179
179
  } | {
180
180
  action: "reset";