@wowok/agent-mcp 2.5.4 → 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.
- package/README.md +33 -26
- package/dist/config/runtime.js +3 -6
- package/dist/harness/checkpoint.js +2 -2
- package/dist/knowledge/flywheel-loop.js +2 -5
- package/dist/knowledge/overrides-loader.js +2 -4
- package/dist/knowledge/progress-ledger.js +3 -0
- package/dist/knowledge/progress-translation.js +5 -1
- package/dist/knowledge/reward-confirm.d.ts +3 -0
- package/dist/knowledge/reward-confirm.js +30 -0
- package/dist/knowledge/reward-puzzle.d.ts +1 -0
- package/dist/knowledge/reward-puzzle.js +12 -0
- package/dist/knowledge/reward-risk.d.ts +4 -1
- package/dist/knowledge/reward-risk.js +85 -3
- package/dist/knowledge/tools-reference.js +5 -4
- package/dist/loop-engineering/improve.js +2 -4
- package/dist/project/deployment-bridge.d.ts +5 -0
- package/dist/project/deployment-bridge.js +96 -0
- package/dist/project/evaluation.d.ts +53 -0
- package/dist/project/evaluation.js +860 -0
- package/dist/project/graph-builder.d.ts +43 -0
- package/dist/project/graph-builder.js +585 -0
- package/dist/project/handlers.d.ts +154 -0
- package/dist/project/handlers.js +567 -0
- package/dist/project/index.d.ts +1 -0
- package/dist/project/index.js +26 -7
- package/dist/project/project-store.js +2 -5
- package/dist/project/query.d.ts +1 -0
- package/dist/project/query.js +2 -0
- package/dist/project/semantic-assembler.d.ts +93 -0
- package/dist/project/semantic-assembler.js +345 -0
- package/dist/schema/call/base.js +1 -1
- package/dist/schema/config/index.d.ts +12 -12
- package/dist/schema/local/index.d.ts +108 -108
- package/dist/schema/local/index.js +21 -18
- package/dist/schema/messenger/index.d.ts +16 -16
- package/dist/schema/messenger/index.js +2 -2
- package/dist/schema/operations.d.ts +0 -6
- package/dist/schema/project/index.d.ts +1840 -3903
- package/dist/schema/project/index.js +403 -955
- package/dist/schema/query/index.d.ts +10 -5
- package/dist/schema/trust/index.d.ts +6 -6
- package/dist/schemas/account_operation.output.json +7 -21
- package/dist/schemas/account_operation.schema.json +9 -23
- package/dist/schemas/bridge_operation.schema.json +1 -1
- package/dist/schemas/guard2file.schema.json +1 -1
- package/dist/schemas/index.json +2 -2
- package/dist/schemas/machineNode2file.schema.json +1 -1
- package/dist/schemas/messenger_operation.schema.json +6 -6
- package/dist/schemas/onchain_operations.schema.json +5 -5
- package/dist/schemas/onchain_operations_allocation.schema.json +1 -1
- package/dist/schemas/onchain_operations_arbitration.schema.json +1 -1
- package/dist/schemas/onchain_operations_contact.schema.json +1 -1
- package/dist/schemas/onchain_operations_demand.schema.json +1 -1
- package/dist/schemas/onchain_operations_gen_passport.schema.json +2 -2
- package/dist/schemas/onchain_operations_gen_proof.schema.json +2 -2
- package/dist/schemas/onchain_operations_guard.schema.json +1 -1
- package/dist/schemas/onchain_operations_machine.schema.json +1 -1
- package/dist/schemas/onchain_operations_order.schema.json +1 -1
- package/dist/schemas/onchain_operations_payment.schema.json +1 -1
- package/dist/schemas/onchain_operations_permission.schema.json +1 -1
- package/dist/schemas/onchain_operations_personal.schema.json +1 -1
- package/dist/schemas/onchain_operations_progress.schema.json +1 -1
- package/dist/schemas/onchain_operations_proof.schema.json +1 -1
- package/dist/schemas/onchain_operations_repository.schema.json +1 -1
- package/dist/schemas/onchain_operations_reward.schema.json +1 -1
- package/dist/schemas/onchain_operations_service.schema.json +1 -1
- package/dist/schemas/onchain_operations_treasury.schema.json +1 -1
- package/dist/schemas/project_operation.output.json +1178 -2494
- package/dist/schemas/project_operation.schema.json +216 -530
- package/dist/schemas/query_toolkit.output.json +7 -6
- package/dist/schemas/query_toolkit.schema.json +0 -4
- package/dist/telemetry/storage.js +2 -2
- package/dist/tools/handlers/onchain.js +110 -19
- package/dist/tools/handlers/project.js +56 -1046
- package/dist/tools/index.js +85 -56
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -25,40 +25,47 @@ Docs: [https://github.com/wowok-ai/docs/](https://github.com/wowok-ai/docs/)
|
|
|
25
25
|
}
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
### 2.
|
|
28
|
+
### 2. Install WoWok Skills (Recommended)
|
|
29
29
|
|
|
30
|
-
**Skills significantly reduce the learning curve and usage difficulty of the MCP Server.**
|
|
30
|
+
**Skills significantly reduce the learning curve and usage difficulty of the MCP Server.** They provide structured guidance for AI assistants on complex system building, tool usage, and safety protocols.
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
|
+
# Personal (global) — available in all sessions:
|
|
33
34
|
npm install -g @wowok/skills
|
|
35
|
+
|
|
36
|
+
# Project (team sharing) — commit to git for collaboration:
|
|
37
|
+
cd your-project
|
|
38
|
+
wowok-skills init # Claude Code (default)
|
|
39
|
+
wowok-skills init --target agents # Trae IDE
|
|
40
|
+
wowok-skills init --target all # All 6 supported clients
|
|
34
41
|
```
|
|
35
42
|
|
|
36
|
-
|
|
43
|
+
**Supported clients:** Claude Code, OpenAI Codex, Trae IDE, CodeBuddy, Cursor, GitHub Copilot.
|
|
44
|
+
|
|
45
|
+
#### Available Skills
|
|
46
|
+
|
|
47
|
+
**Always loaded** (3 skills — foundational layer):
|
|
37
48
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
-
|
|
49
|
+
| Skill | Purpose |
|
|
50
|
+
|-------|---------|
|
|
51
|
+
| `wowok-tools` | MCP tool reference — 17 sub-tools, schema-gated execution, constraints |
|
|
52
|
+
| `wowok-safety` | Safety protocol — dry-run → confirm → execute, immutability rules |
|
|
53
|
+
| `wowok-output` | Output processing — address resolution, name mapping, data visualization |
|
|
41
54
|
|
|
42
|
-
|
|
55
|
+
**On-demand** (11 skills — loaded by context):
|
|
43
56
|
|
|
44
57
|
| Skill | Role | Purpose |
|
|
45
58
|
|-------|------|---------|
|
|
46
|
-
| `wowok-
|
|
47
|
-
| `wowok-
|
|
48
|
-
| `wowok-
|
|
49
|
-
| `wowok-arbitrator` | ⚖️ Arbitrator | Arbitration service — dispute resolution, voting
|
|
50
|
-
| `wowok-guard` | 🛠️ Shared | Guard design
|
|
51
|
-
| `wowok-messenger` | 🛠️ Shared | Encrypted messaging — E2E communication, WTS evidence,
|
|
52
|
-
| `wowok-
|
|
53
|
-
| `wowok-
|
|
54
|
-
| `wowok-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
- **Use `wowok-provider`** + `wowok-machine` when user is a merchant/service provider
|
|
60
|
-
- **Use `wowok-arbitrator`** when user operates dispute resolution services
|
|
61
|
-
- **Use `wowok-tools`** + `wowok-safety`** + `wowok-output` (always loaded) for all roles
|
|
62
|
-
- **Use `wowok-guard`** when designing complex validation rules
|
|
63
|
-
|
|
64
|
-
> **Note:** For detailed installation instructions for different AI clients (Claude Code, OpenAI Codex, Trae IDE, Cursor, etc.), see the [WoWok Skills](https://github.com/wowok-ai/skills) repository.
|
|
59
|
+
| `wowok-provider` | 🏪 Provider | Service provider guide — create Service, Machine, Allocators, order fulfillment |
|
|
60
|
+
| `wowok-machine` | 🏪 Provider | Workflow design — state machines, node/pair/forward graph, publish lifecycle |
|
|
61
|
+
| `wowok-order` | 👤 Customer | Order lifecycle — due diligence, consensus, order creation, progress, arbitration |
|
|
62
|
+
| `wowok-arbitrator` | ⚖️ Arbitrator | Arbitration service — dispute resolution, weighted voting, fee management |
|
|
63
|
+
| `wowok-guard` | 🛠️ Shared | Guard design — programmable trust rules, 4 data sources, 33 constraints |
|
|
64
|
+
| `wowok-messenger` | 🛠️ Shared | Encrypted messaging — E2E communication, WTS evidence, anti-spam |
|
|
65
|
+
| `wowok-onboard` | 🆕 New User | First-touch onboarding — 10-round dialogue from zero to first published Service |
|
|
66
|
+
| `wowok-scenario` | 🛠️ Shared | Industry mode templates — freelance, rental, education, travel presets |
|
|
67
|
+
| `wowok-planner` | 🛠️ Shared | Planning — converts natural language intent into Object Dependency Graph (ODG) |
|
|
68
|
+
| `wowok-auditor` | 🛠️ Shared | Pre-publish audit — Guard completeness, Machine soundness, 32 audit checks |
|
|
69
|
+
| `wowok-distill` | 🏪 Provider | Distillation review — review AI-generated improvement proposals |
|
|
70
|
+
|
|
71
|
+
> **Tip:** `wowok-tools` + `wowok-safety` + `wowok-output` are always loaded and serve all roles. Add role-specific skills (`wowok-provider`, `wowok-order`, `wowok-arbitrator`) as needed.
|
package/dist/config/runtime.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
2
2
|
import { dirname, join } from "path";
|
|
3
|
-
import {
|
|
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
|
-
|
|
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 ~/.
|
|
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 {
|
|
4
|
-
const CHECKPOINT_ROOT = join(
|
|
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 {
|
|
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
|
-
|
|
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 {
|
|
3
|
+
import { getWowMcpDir } from "@wowok/wowok";
|
|
4
4
|
function wowokRootDir() {
|
|
5
|
-
return
|
|
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",
|
|
@@ -81,6 +81,7 @@ export interface RewardJsonForConfirm {
|
|
|
81
81
|
guard_expiration_time?: number | null;
|
|
82
82
|
owner_receive?: unknown;
|
|
83
83
|
um?: string | null;
|
|
84
|
+
guard_expected_progress_state?: string;
|
|
84
85
|
}
|
|
85
86
|
export interface RewardConfirmGateInput {
|
|
86
87
|
reward_json: RewardJsonForConfirm;
|
|
@@ -97,6 +98,8 @@ export interface RewardConfirmGateInput {
|
|
|
97
98
|
passport_submission_value_types?: Record<number, string>;
|
|
98
99
|
passport_identifier_is_address?: Record<number, boolean>;
|
|
99
100
|
guard_store_from_id_compatible?: Record<string, boolean>;
|
|
101
|
+
user_intent_phrases?: string[];
|
|
102
|
+
machine_has_wonder_node?: boolean;
|
|
100
103
|
skip_user_confirmation?: boolean;
|
|
101
104
|
skip_environment_check?: boolean;
|
|
102
105
|
}
|
|
@@ -11,6 +11,7 @@ export const REWARD_OPERATION_CHECKLIST = [
|
|
|
11
11
|
{ id: "C-R-08", description: "claim: Passport is provided (SDK W_ERROR if missing)", passed: false, message: "" },
|
|
12
12
|
{ id: "C-R-09", description: "owner_receive (156): user double-confirms blast radius", passed: false, message: "" },
|
|
13
13
|
{ id: "C-R-10", description: "guard_expiration_time_add (155): new time > current clock", passed: false, message: "" },
|
|
14
|
+
{ id: "C-R-11", description: "guard_add: Guard's progress.current expected value matches business intent (praise→wonder, completion→completed)", passed: false, message: "" },
|
|
14
15
|
];
|
|
15
16
|
function runStaticChecklist(input) {
|
|
16
17
|
const items = REWARD_OPERATION_CHECKLIST.map(c => ({ ...c }));
|
|
@@ -133,6 +134,22 @@ function runStaticChecklist(input) {
|
|
|
133
134
|
else {
|
|
134
135
|
cr10.passed = true;
|
|
135
136
|
}
|
|
137
|
+
const cr11 = items.find(i => i.id === "C-R-11");
|
|
138
|
+
if (data.guard_expected_progress_state && input.user_intent_phrases && input.user_intent_phrases.length > 0) {
|
|
139
|
+
const intentLower = input.user_intent_phrases.join(" ").toLowerCase();
|
|
140
|
+
const praiseKeywords = ["好评", "praise", "wonder", "thumbs_up", "positive review", "satisfaction reward", "好评奖励"];
|
|
141
|
+
const isPraiseIntent = praiseKeywords.some(kw => intentLower.includes(kw.toLowerCase()));
|
|
142
|
+
if (isPraiseIntent && input.machine_has_wonder_node !== false && data.guard_expected_progress_state !== "wonder") {
|
|
143
|
+
cr11.passed = false;
|
|
144
|
+
cr11.message = `intent=praise but Guard checks "${data.guard_expected_progress_state}" instead of "wonder" — R-R-6-01 violation`;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
cr11.passed = true;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
cr11.passed = true;
|
|
152
|
+
}
|
|
136
153
|
return {
|
|
137
154
|
all_passed: items.filter(i => i.id !== "C-R-09").every(i => i.passed),
|
|
138
155
|
items,
|
|
@@ -162,6 +179,9 @@ function adaptRiskAssessment(input) {
|
|
|
162
179
|
passport_submission_value_types: input.passport_submission_value_types,
|
|
163
180
|
passport_identifier_is_address: input.passport_identifier_is_address,
|
|
164
181
|
guard_store_from_id_compatible: input.guard_store_from_id_compatible,
|
|
182
|
+
user_intent_phrases: input.user_intent_phrases,
|
|
183
|
+
guard_expected_progress_state: input.reward_json.guard_expected_progress_state,
|
|
184
|
+
machine_has_wonder_node: input.machine_has_wonder_node,
|
|
165
185
|
};
|
|
166
186
|
return assessRewardRisks(ctx);
|
|
167
187
|
}
|
|
@@ -201,6 +221,14 @@ export const REWARD_CONFIRMATION_QUESTIONS = [
|
|
|
201
221
|
requires_explicit_yes: false,
|
|
202
222
|
related_risk_ids: ["R-R-5-02"],
|
|
203
223
|
},
|
|
224
|
+
{
|
|
225
|
+
id: "QRW7",
|
|
226
|
+
question: "⚠️ For guard_add with progress.current check: does the Guard's expected progress node match the business intent? " +
|
|
227
|
+
"If intent is '好评/praise', Guard must check 'wonder' (NOT 'completed'). " +
|
|
228
|
+
"Premature claim at wrong node drains reward pool — Guard is immutable after creation.",
|
|
229
|
+
requires_explicit_yes: true,
|
|
230
|
+
related_risk_ids: ["R-R-6-01", "R-R-6-02"],
|
|
231
|
+
},
|
|
204
232
|
];
|
|
205
233
|
function processUserConfirmation(input, assessment) {
|
|
206
234
|
const questions = [...REWARD_CONFIRMATION_QUESTIONS];
|
|
@@ -217,6 +245,8 @@ function processUserConfirmation(input, assessment) {
|
|
|
217
245
|
continue;
|
|
218
246
|
if (q.id === "QRW6" && !data.coin_add)
|
|
219
247
|
continue;
|
|
248
|
+
if (q.id === "QRW7" && (!data.guard_add || !data.guard_expected_progress_state))
|
|
249
|
+
continue;
|
|
220
250
|
filtered.push(q);
|
|
221
251
|
}
|
|
222
252
|
if (input.skip_user_confirmation) {
|
|
@@ -48,6 +48,7 @@ export interface RewardConstraintChecklist {
|
|
|
48
48
|
F_R_06_recipient_amount_valid_pairing: boolean;
|
|
49
49
|
F_R_07_coin_type_matches_reward_t: boolean;
|
|
50
50
|
F_R_08_passport_required_for_claim: boolean;
|
|
51
|
+
F_R_09_progress_node_matches_intent: boolean;
|
|
51
52
|
}
|
|
52
53
|
export type RewardPuzzleDimension = "A" | "B" | "C" | "D" | "E" | "F";
|
|
53
54
|
export interface RewardPuzzle {
|
|
@@ -29,6 +29,7 @@ export function initPuzzleFromIntent(intent) {
|
|
|
29
29
|
F_R_06_recipient_amount_valid_pairing: false,
|
|
30
30
|
F_R_07_coin_type_matches_reward_t: false,
|
|
31
31
|
F_R_08_passport_required_for_claim: false,
|
|
32
|
+
F_R_09_progress_node_matches_intent: true,
|
|
32
33
|
};
|
|
33
34
|
return puzzle;
|
|
34
35
|
}
|
|
@@ -177,6 +178,17 @@ export function validateConstraints(puzzle) {
|
|
|
177
178
|
message: "claim requires Passport — SDK W_ERROR if missing",
|
|
178
179
|
});
|
|
179
180
|
}
|
|
181
|
+
if (puzzle.guard && puzzle.intent && puzzle.constraints) {
|
|
182
|
+
if (!puzzle.constraints.F_R_09_progress_node_matches_intent) {
|
|
183
|
+
violations.push({
|
|
184
|
+
constraint_id: "F-R-09",
|
|
185
|
+
severity: "HIGH",
|
|
186
|
+
message: "Guard's expected progress.current value does not match business intent — " +
|
|
187
|
+
"praise reward (好评/wonder) must check 'wonder' node, not 'completed'. " +
|
|
188
|
+
"Guard is immutable after creation; mismatch requires full rebuild.",
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
180
192
|
return violations;
|
|
181
193
|
}
|
|
182
194
|
export function generateConfirmationText(puzzle) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type RewardScene, type RewardAmountType } from "./reward-ledger.js";
|
|
2
2
|
export type RewardRiskLevel = "CRITICAL" | "HIGH" | "MEDIUM" | "LOW";
|
|
3
|
-
export type RewardRiskCategory = "structural" | "semantic" | "permission" | "lifecycle" | "cross_object";
|
|
3
|
+
export type RewardRiskCategory = "structural" | "semantic" | "permission" | "lifecycle" | "cross_object" | "business_semantic";
|
|
4
4
|
export interface RewardRisk {
|
|
5
5
|
id: string;
|
|
6
6
|
level: RewardRiskLevel;
|
|
@@ -65,6 +65,9 @@ export interface RewardRiskCheckContext {
|
|
|
65
65
|
passport_submission_value_types?: Record<number, string>;
|
|
66
66
|
passport_identifier_is_address?: Record<number, boolean>;
|
|
67
67
|
guard_store_from_id_compatible?: Record<string, boolean>;
|
|
68
|
+
user_intent_phrases?: string[];
|
|
69
|
+
guard_expected_progress_state?: string;
|
|
70
|
+
machine_has_wonder_node?: boolean;
|
|
68
71
|
}
|
|
69
72
|
export declare const REWARD_RISK_VERSION = "1.0.0";
|
|
70
73
|
export declare function getAllRewardRiskRules(): RewardRiskRule[];
|
|
@@ -469,12 +469,94 @@ const R_R_5_03 = {
|
|
|
469
469
|
return null;
|
|
470
470
|
},
|
|
471
471
|
};
|
|
472
|
+
const R_R_6_01 = {
|
|
473
|
+
id: "R-R-6-01",
|
|
474
|
+
category: "business_semantic",
|
|
475
|
+
trigger: "intent mentions praise/好评 but Guard checks non-wonder progress node",
|
|
476
|
+
check: (ctx) => {
|
|
477
|
+
if (!ctx.user_intent_phrases || ctx.user_intent_phrases.length === 0)
|
|
478
|
+
return null;
|
|
479
|
+
if (!ctx.guard_expected_progress_state)
|
|
480
|
+
return null;
|
|
481
|
+
const intentLower = ctx.user_intent_phrases.join(" ").toLowerCase();
|
|
482
|
+
const praiseKeywords = [
|
|
483
|
+
"好评", "praise", "wonder", "thumbs_up",
|
|
484
|
+
"positive review", "satisfaction reward", "好评奖励",
|
|
485
|
+
];
|
|
486
|
+
const isPraiseIntent = praiseKeywords.some(kw => intentLower.includes(kw.toLowerCase()));
|
|
487
|
+
if (!isPraiseIntent)
|
|
488
|
+
return null;
|
|
489
|
+
if (ctx.machine_has_wonder_node === false)
|
|
490
|
+
return null;
|
|
491
|
+
const expected = ctx.guard_expected_progress_state;
|
|
492
|
+
if (expected !== "wonder") {
|
|
493
|
+
return {
|
|
494
|
+
id: "R-R-6-01",
|
|
495
|
+
level: "HIGH",
|
|
496
|
+
category: "business_semantic",
|
|
497
|
+
title: `Guard checks progress=="${expected}" but intent indicates praise reward (wonder node)`,
|
|
498
|
+
description: `User intent mentions praise/好评/wonder, which maps to the 'wonder' progress node ` +
|
|
499
|
+
`(customer gives positive review AFTER service completion). But the Guard's table bakes ` +
|
|
500
|
+
`expected state="${expected}", allowing reward claim at the wrong lifecycle stage. ` +
|
|
501
|
+
`This violates the business semantics: "好评奖励" should only be claimable AFTER the ` +
|
|
502
|
+
`customer advances to the 'wonder' node, not before. ` +
|
|
503
|
+
`Guard is immutable — fixing this requires creating a new Guard + Reward pair.`,
|
|
504
|
+
affected_stakeholders: ["owner", "service_provider", "claimer"],
|
|
505
|
+
scenario: "Designer builds Guard checking 'completed' instead of 'wonder' for a praise reward",
|
|
506
|
+
mitigation: "Set the Guard table's expected progress state to 'wonder' (the positive-review node). " +
|
|
507
|
+
"The correct pattern: ordered → in_service → completed → wonder (praise) triggers reward claim. " +
|
|
508
|
+
"Reference: reward-templates.ts wonder_praise template.",
|
|
509
|
+
evidence: `intent="${intentLower}", expected_state="${expected}", expected_wonder=true`,
|
|
510
|
+
auto_fixable: false,
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
return null;
|
|
514
|
+
},
|
|
515
|
+
};
|
|
516
|
+
const R_R_6_02 = {
|
|
517
|
+
id: "R-R-6-02",
|
|
518
|
+
category: "business_semantic",
|
|
519
|
+
trigger: "Guard checks wonder node but intent does not mention praise",
|
|
520
|
+
check: (ctx) => {
|
|
521
|
+
if (!ctx.user_intent_phrases || ctx.user_intent_phrases.length === 0)
|
|
522
|
+
return null;
|
|
523
|
+
if (!ctx.guard_expected_progress_state)
|
|
524
|
+
return null;
|
|
525
|
+
if (ctx.guard_expected_progress_state !== "wonder")
|
|
526
|
+
return null;
|
|
527
|
+
const intentLower = ctx.user_intent_phrases.join(" ").toLowerCase();
|
|
528
|
+
const praiseKeywords = [
|
|
529
|
+
"好评", "praise", "wonder", "thumbs_up",
|
|
530
|
+
"positive review", "satisfaction reward", "好评奖励",
|
|
531
|
+
];
|
|
532
|
+
const isPraiseIntent = praiseKeywords.some(kw => intentLower.includes(kw.toLowerCase()));
|
|
533
|
+
if (isPraiseIntent)
|
|
534
|
+
return null;
|
|
535
|
+
return {
|
|
536
|
+
id: "R-R-6-02",
|
|
537
|
+
level: "MEDIUM",
|
|
538
|
+
category: "business_semantic",
|
|
539
|
+
title: "Guard checks wonder node but intent does not mention praise",
|
|
540
|
+
description: `Guard's expected progress state is "wonder" (positive-review node), but the user intent ` +
|
|
541
|
+
`does not mention any praise/好评 keyword. This may be a copy-paste from a wonder_praise ` +
|
|
542
|
+
`template without adjusting the Guard for the actual business semantics. If this is a ` +
|
|
543
|
+
`general feedback reward (wonder_feedback), this is fine. Otherwise, verify the node choice.`,
|
|
544
|
+
affected_stakeholders: ["owner"],
|
|
545
|
+
scenario: "Designer copies wonder_praise template but actually wants a completion-based reward",
|
|
546
|
+
mitigation: "Verify: if intent is praise reward, add '好评/praise' to description. " +
|
|
547
|
+
"If intent is completion-based reward, change Guard to check 'completed' node.",
|
|
548
|
+
evidence: `expected_state="wonder", intent="${intentLower}" (no praise keyword)`,
|
|
549
|
+
auto_fixable: false,
|
|
550
|
+
};
|
|
551
|
+
},
|
|
552
|
+
};
|
|
472
553
|
const ALL_RULES = [
|
|
473
554
|
R_R_1_01, R_R_1_02, R_R_1_03,
|
|
474
555
|
R_R_2_01, R_R_2_02, R_R_2_03, R_R_2_04,
|
|
475
556
|
R_R_3_01, R_R_3_02, R_R_3_03,
|
|
476
557
|
R_R_4_01, R_R_4_02, R_R_4_03, R_R_4_04,
|
|
477
558
|
R_R_5_01, R_R_5_02, R_R_5_03,
|
|
559
|
+
R_R_6_01, R_R_6_02,
|
|
478
560
|
];
|
|
479
561
|
export const REWARD_RISK_VERSION = "1.0.0";
|
|
480
562
|
export function getAllRewardRiskRules() {
|
|
@@ -529,13 +611,13 @@ export const REWARD_STAKEHOLDERS = [
|
|
|
529
611
|
export function getRewardRiskRulesByStakeholder(stakeholder) {
|
|
530
612
|
return ALL_RULES.filter(rule => {
|
|
531
613
|
if (stakeholder === "owner") {
|
|
532
|
-
return ["structural", "permission", "lifecycle"].includes(rule.category);
|
|
614
|
+
return ["structural", "permission", "lifecycle", "business_semantic"].includes(rule.category);
|
|
533
615
|
}
|
|
534
616
|
if (stakeholder === "claimer") {
|
|
535
|
-
return rule.id.startsWith("R-R-4-0") || rule.id === "R-R-5-01" || rule.id === "R-R-1-02";
|
|
617
|
+
return rule.id.startsWith("R-R-4-0") || rule.id === "R-R-5-01" || rule.id === "R-R-1-02" || rule.id === "R-R-6-01";
|
|
536
618
|
}
|
|
537
619
|
if (stakeholder === "service_provider") {
|
|
538
|
-
return rule.id === "R-R-4-02" || rule.id === "R-R-3-01" || rule.id === "R-R-3-02";
|
|
620
|
+
return rule.id === "R-R-4-02" || rule.id === "R-R-3-01" || rule.id === "R-R-3-02" || rule.id === "R-R-6-01";
|
|
539
621
|
}
|
|
540
622
|
if (stakeholder === "system") {
|
|
541
623
|
return rule.category === "cross_object";
|
|
@@ -105,11 +105,12 @@ export const TOOLS_REFERENCE = [
|
|
|
105
105
|
},
|
|
106
106
|
{
|
|
107
107
|
name: "project_operation",
|
|
108
|
-
summary: "Project
|
|
109
|
-
actions: ["list_projects", "
|
|
108
|
+
summary: "Project entity management (SQLite) + 3-pathway graph construction + dual rule-based/LLM-assisted evaluation engine.",
|
|
109
|
+
actions: ["list_projects", "create_project", "create_project_from_onchain", "update_project", "get_project_detail", "add_object", "remove_object", "create_version", "build_graph", "get_graph", "evaluate_project", "save_evaluation", "compare_projects", "refresh_objects", "get_object_diff", "assemble_context"],
|
|
110
110
|
notes: [
|
|
111
|
-
"
|
|
112
|
-
"
|
|
111
|
+
"GLM6: Projects are first-class entities with SQLite persistence, rigid project-object relationships.",
|
|
112
|
+
"Evaluation: risk/trust/completeness are rule-based (computed locally). value/worth_buying require LLM assistance (returns a prompt).",
|
|
113
|
+
"Graph: 3 pathways — internal references (configurable depth), Registrar inbound (O(1)), potential relationships.",
|
|
113
114
|
],
|
|
114
115
|
},
|
|
115
116
|
{
|
|
@@ -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 {
|
|
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
|
|
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,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
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Project, ProjectObject, GraphEdge, ObjectCacheEntry, EvaluationType } from "@wowok/wowok";
|
|
2
|
+
import type { ReputationData } from "./graph-builder.js";
|
|
3
|
+
export interface CriterionScore {
|
|
4
|
+
name: string;
|
|
5
|
+
score: number;
|
|
6
|
+
weight: number;
|
|
7
|
+
rationale: string;
|
|
8
|
+
}
|
|
9
|
+
export interface EvaluationFinding {
|
|
10
|
+
criterion: string;
|
|
11
|
+
severity: "critical" | "warning" | "info";
|
|
12
|
+
message: string;
|
|
13
|
+
deduction: number;
|
|
14
|
+
}
|
|
15
|
+
export interface EvaluationResult {
|
|
16
|
+
evaluationType: EvaluationType;
|
|
17
|
+
score: number;
|
|
18
|
+
summary: string;
|
|
19
|
+
criterionScores: CriterionScore[];
|
|
20
|
+
findings: EvaluationFinding[];
|
|
21
|
+
strengths: string[];
|
|
22
|
+
needsLlm: boolean;
|
|
23
|
+
llmPrompt?: string;
|
|
24
|
+
evaluatedAt: number;
|
|
25
|
+
}
|
|
26
|
+
export interface EvaluationInput {
|
|
27
|
+
project: Project;
|
|
28
|
+
objects: ProjectObject[];
|
|
29
|
+
edges: GraphEdge[];
|
|
30
|
+
objectCache: Map<string, ObjectCacheEntry>;
|
|
31
|
+
reputation?: Map<string, ReputationData>;
|
|
32
|
+
}
|
|
33
|
+
export declare function runEvaluation(input: EvaluationInput, evaluationType: EvaluationType, llmPrompt?: string): EvaluationResult;
|
|
34
|
+
export interface ProjectComparisonEntry {
|
|
35
|
+
projectId: string;
|
|
36
|
+
projectName: string;
|
|
37
|
+
score: number | null;
|
|
38
|
+
summary: string | null;
|
|
39
|
+
evaluatedAt: number | null;
|
|
40
|
+
}
|
|
41
|
+
export interface ProjectComparison {
|
|
42
|
+
evaluationType: EvaluationType;
|
|
43
|
+
entries: ProjectComparisonEntry[];
|
|
44
|
+
ranking: ProjectComparisonEntry[];
|
|
45
|
+
bestProjectId: string | null;
|
|
46
|
+
}
|
|
47
|
+
export declare function compareProjects(entries: Array<{
|
|
48
|
+
projectId: string;
|
|
49
|
+
projectName: string;
|
|
50
|
+
score: number | null;
|
|
51
|
+
summary: string | null;
|
|
52
|
+
evaluatedAt: number | null;
|
|
53
|
+
}>, evaluationType: EvaluationType): ProjectComparison;
|