forge-openclaw-plugin 0.2.40 → 0.2.42
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/assets/index-Fe5y4VWU.js +91 -0
- package/dist/assets/{index-46NL_IaJ.js.map → index-Fe5y4VWU.js.map} +1 -1
- package/dist/index.html +1 -1
- package/dist/openclaw/plugin-sdk-types.d.ts +6 -0
- package/dist/openclaw/routes.js +10 -1
- package/dist/server/server/src/app.js +37 -11
- package/dist/server/server/src/movement.js +79 -5
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/skills/forge-openclaw/SKILL.md +2 -0
- package/skills/forge-openclaw/entity_conversation_playbooks.md +20 -3
- package/skills/forge-openclaw/psyche_entity_playbooks.md +10 -3
- package/dist/assets/index-46NL_IaJ.js +0 -91
package/dist/index.html
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
/>
|
|
14
14
|
<link rel="icon" type="image/png" href="/forge/assets/favicon-BCHm9dUV.ico" />
|
|
15
15
|
<link rel="alternate icon" href="/forge/assets/favicon-BCHm9dUV.ico" />
|
|
16
|
-
<script type="module" crossorigin src="/forge/assets/index-
|
|
16
|
+
<script type="module" crossorigin src="/forge/assets/index-Fe5y4VWU.js"></script>
|
|
17
17
|
<link rel="modulepreload" crossorigin href="/forge/assets/vendor-DK-mJFy6.js">
|
|
18
18
|
<link rel="modulepreload" crossorigin href="/forge/assets/board-C3BJqvZu.js">
|
|
19
19
|
<link rel="modulepreload" crossorigin href="/forge/assets/ui-CQzq3TE5.js">
|
|
@@ -42,6 +42,11 @@ export type ForgeCliRegistrarContext = {
|
|
|
42
42
|
debug?(message: string): void;
|
|
43
43
|
};
|
|
44
44
|
};
|
|
45
|
+
export type ForgeCliCommandDescriptor = {
|
|
46
|
+
name: string;
|
|
47
|
+
description: string;
|
|
48
|
+
hasSubcommands?: boolean;
|
|
49
|
+
};
|
|
45
50
|
export type ForgePluginServiceContext = {
|
|
46
51
|
config?: unknown;
|
|
47
52
|
workspaceDir?: string;
|
|
@@ -77,6 +82,7 @@ export type ForgePluginRegistrationApi = {
|
|
|
77
82
|
}): void;
|
|
78
83
|
registerCli?(registrar: (context: ForgeCliRegistrarContext) => void, options?: {
|
|
79
84
|
commands?: string[];
|
|
85
|
+
descriptors?: ForgeCliCommandDescriptor[];
|
|
80
86
|
}): void;
|
|
81
87
|
registerService?(service: ForgeRegisteredService): void;
|
|
82
88
|
};
|
package/dist/openclaw/routes.js
CHANGED
|
@@ -1158,5 +1158,14 @@ export function registerForgePluginCli(api, config) {
|
|
|
1158
1158
|
.action(async () => {
|
|
1159
1159
|
console.log(JSON.stringify(await runRouteCheck(config), null, 2));
|
|
1160
1160
|
});
|
|
1161
|
-
}, {
|
|
1161
|
+
}, {
|
|
1162
|
+
commands: ["forge"],
|
|
1163
|
+
descriptors: [
|
|
1164
|
+
{
|
|
1165
|
+
name: "forge",
|
|
1166
|
+
description: "Inspect and operate Forge through the OpenClaw plugin",
|
|
1167
|
+
hasSubcommands: true
|
|
1168
|
+
}
|
|
1169
|
+
]
|
|
1170
|
+
});
|
|
1162
1171
|
}
|
|
@@ -62,7 +62,7 @@ import { registerWebRoutes } from "./web.js";
|
|
|
62
62
|
import { createManagerRuntime } from "./managers/runtime.js";
|
|
63
63
|
import { isManagerError } from "./managers/type-guards.js";
|
|
64
64
|
import { createCompanionPairingSession, createCompanionPairingSessionSchema, createSleepSession, createSleepSessionSchema, createWorkoutSession, createWorkoutSessionSchema, deleteSleepSession, deleteWorkoutSession, getCompanionPairingSessionById, getCompanionOverview, getFitnessViewData, getSleepSessionById, getSleepSessionDetailById, getSleepViewData, getVitalsViewData, getWorkoutSessionById, ingestMobileHealthSync, mobileHealthSyncSchema, patchCompanionPairingSourceState, patchCompanionPairingSourceStateSchema, companionSourceKeySchema, requireValidPairing, revokeAllCompanionPairingSessions, revokeAllCompanionPairingSessionsSchema, revokeCompanionPairingSession, updateMobileCompanionSourceState, updateMobileCompanionSourceStateSchema, verifyCompanionPairing, verifyCompanionPairingSchema, updateSleepMetadata, updateSleepMetadataSchema, updateWorkoutMetadata, updateWorkoutMetadataSchema } from "./health.js";
|
|
65
|
-
import { analyzeMovementUserBoxPreflight, createMovementUserBox, createMovementPlace, deleteMovementUserBox, getMovementAllTimeSummary, getMovementBoxDetail, getMovementDayDetail, getMovementMobileBootstrap, getMovementTimeline, getMovementSelectionAggregate, getMovementSettings, getMovementTripDetail, getMovementMonthSummary, invalidateAutomaticMovementBox, listMovementPlaces, movementAutomaticBoxInvalidateSchema, movementMobileBootstrapSchema, movementMobilePlaceMutationSchema, movementMobileUserBoxCreateSchema, movementMobileUserBoxPreflightSchema, movementMobileUserBoxPatchSchema, movementMobileAutomaticBoxInvalidateSchema, movementMobileTimelineSchema, movementPlaceMutationSchema, movementPlacePatchSchema, movementSelectionAggregateSchema, movementStayPatchSchema, movementTripPatchSchema, movementUserBoxCreateSchema, movementUserBoxPreflightSchema, movementUserBoxPatchSchema, movementSettingsPatchSchema, movementTimelineQuerySchema, movementTripPointPatchSchema, deleteMovementStay, deleteMovementTrip, deleteMovementTripPoint, updateMovementPlace, updateMovementSettings, updateMovementStay, updateMovementTrip, updateMovementUserBox, updateMovementTripPoint, resolveMovementTimelineSegmentForBox } from "./movement.js";
|
|
65
|
+
import { analyzeMovementUserBoxPreflight, createMovementUserBox, createMovementPlace, deleteMovementUserBox, getMovementAllTimeSummary, getMovementBoxDetail, getMovementDayDetail, getMovementMobileBootstrap, getMovementTimeline, getMovementSelectionAggregate, getMovementSettings, getMovementTripDetail, getMovementMonthSummary, invalidateAutomaticMovementBox, listMovementPlaces, movementAutomaticBoxInvalidateSchema, movementMobileBootstrapSchema, movementMobilePlaceMutationSchema, movementMobileStayPatchSchema, movementMobileUserBoxCreateSchema, movementMobileUserBoxPreflightSchema, movementMobileUserBoxPatchSchema, movementMobileAutomaticBoxInvalidateSchema, movementMobileTimelineSchema, movementPlaceMutationSchema, movementPlacePatchSchema, movementSelectionAggregateSchema, movementStayPatchSchema, movementTripPatchSchema, movementUserBoxCreateSchema, movementUserBoxPreflightSchema, movementUserBoxPatchSchema, movementSettingsPatchSchema, movementTimelineQuerySchema, movementTripPointPatchSchema, deleteMovementStay, deleteMovementTrip, deleteMovementTripPoint, updateMovementPlace, updateMovementSettings, updateMovementStay, updateMovementTrip, updateMovementUserBox, updateMovementTripPoint, resolveMovementTimelineSegmentForBox } from "./movement.js";
|
|
66
66
|
import { getScreenTimeAllTimeSummary, getScreenTimeDayDetail, getScreenTimeMonthSummary, getScreenTimeSettings, screenTimeSettingsPatchSchema, updateScreenTimeSettings } from "./screen-time.js";
|
|
67
67
|
import { assertWatchReady, buildWatchBootstrap, ingestWatchCaptureBatch, mobileWatchBootstrapSchema, mobileWatchCaptureBatchSchema, mobileWatchHabitCheckInSchema } from "./watch-mobile.js";
|
|
68
68
|
const COMPATIBILITY_SUNSET = "transitional-node";
|
|
@@ -2654,7 +2654,8 @@ const AGENT_ONBOARDING_ENTITY_CATALOG = [
|
|
|
2654
2654
|
],
|
|
2655
2655
|
searchHints: [
|
|
2656
2656
|
"Clarify whether the user wants a behavioral query, one trip or place, a missing-gap overlay, a manual add or update, or a link before choosing the route.",
|
|
2657
|
-
"If the user already named a concrete missing span, confirm only the remaining time or place ambiguity, then use the movement overlay route and read the timeline back."
|
|
2657
|
+
"If the user already named a concrete missing span, confirm only the remaining time or place ambiguity, then use the movement overlay route and read the timeline back.",
|
|
2658
|
+
"If the user wants to revise or remove an already-saved correction, identify whether it is a user-defined box, automatic box, recorded stay, recorded trip, or trip point before choosing the repair or delete route."
|
|
2658
2659
|
],
|
|
2659
2660
|
fieldGuide: []
|
|
2660
2661
|
}),
|
|
@@ -2668,7 +2669,8 @@ const AGENT_ONBOARDING_ENTITY_CATALOG = [
|
|
|
2668
2669
|
],
|
|
2669
2670
|
searchHints: [
|
|
2670
2671
|
"Clarify whether the user wants explanation, durable model changes, or a real-time tired or recovered signal before choosing the route.",
|
|
2671
|
-
"Separate durable profile assumptions, weekday-template edits, and right-now fatigue signals before choosing the mutation path."
|
|
2672
|
+
"Separate durable profile assumptions, weekday-template edits, and right-now fatigue signals before choosing the mutation path.",
|
|
2673
|
+
"When the user is trying to understand the practical result of a change, read the overview again after the write instead of stopping at the mutation response."
|
|
2672
2674
|
],
|
|
2673
2675
|
fieldGuide: []
|
|
2674
2676
|
}),
|
|
@@ -2682,7 +2684,8 @@ const AGENT_ONBOARDING_ENTITY_CATALOG = [
|
|
|
2682
2684
|
],
|
|
2683
2685
|
searchHints: [
|
|
2684
2686
|
"Clarify whether the user wants flow discovery, editing, execution, published output, run inspection, or node-level output before choosing the route.",
|
|
2685
|
-
"Distinguish flow contract, published output, run history,
|
|
2687
|
+
"Distinguish flow contract, published output, run history, latest-node-output, and chat follow-up questions before reaching for a route.",
|
|
2688
|
+
"If the user is still deciding how to run or edit a flow, read flow detail or the box catalog before asking them for payload structure."
|
|
2686
2689
|
],
|
|
2687
2690
|
fieldGuide: []
|
|
2688
2691
|
}),
|
|
@@ -3061,7 +3064,7 @@ const AGENT_ONBOARDING_ENTITY_CONVERSATION_PLAYBOOKS = [
|
|
|
3061
3064
|
},
|
|
3062
3065
|
{
|
|
3063
3066
|
focus: "movement",
|
|
3064
|
-
openingQuestion: "
|
|
3067
|
+
openingQuestion: "What are you trying to understand, correct, or preserve about where you stayed and traveled?",
|
|
3065
3068
|
coachingGoal: "Clarify whether the user wants a time-in-place query, travel-history review, a missing-gap overlay, one stay or trip change, one place summary, or a link before choosing the dedicated movement route.",
|
|
3066
3069
|
askSequence: [
|
|
3067
3070
|
"Ask whether the user is trying to query behavior, add something manually, update an existing movement item, or link movement to another Forge entity.",
|
|
@@ -3071,6 +3074,7 @@ const AGENT_ONBOARDING_ENTITY_CONVERSATION_PLAYBOOKS = [
|
|
|
3071
3074
|
"Skip the meta lane question when the user already named the exact correction or review target and only one ambiguity remains.",
|
|
3072
3075
|
"If the request is filling a missing-data gap, use a user-defined movement box rather than a raw stay or trip patch.",
|
|
3073
3076
|
"If the request is repairing already-saved movement data, use the repair route that matches the saved object instead of treating it like a missing span.",
|
|
3077
|
+
"If the request is removing an already-saved correction, identify whether it is a user-defined box, recorded stay, recorded trip, or trip point before choosing the delete route.",
|
|
3074
3078
|
"When the user wants place creation or place cleanup, use the dedicated movement place routes rather than a generic entity mutation.",
|
|
3075
3079
|
"When the user already gave a concrete correction like 'I stayed home during that missing block', confirm only the interval or place if needed, then create the overlay and read the timeline back."
|
|
3076
3080
|
]
|
|
@@ -3086,12 +3090,13 @@ const AGENT_ONBOARDING_ENTITY_CONVERSATION_PLAYBOOKS = [
|
|
|
3086
3090
|
"Ask whether the user is describing a stable weekly shape or just how today feels when the lane is still blurred.",
|
|
3087
3091
|
"If the user already named the life-force lane clearly, skip the meta lane question and ask only for the specific weekday, profile field, or signal that still matters.",
|
|
3088
3092
|
"If the request is about a durable baseline, use profile or weekday-template mutation rather than a fatigue signal; if it is about right now, prefer the fatigue-signal route.",
|
|
3093
|
+
"If the user wants to see what changed after a write, read the overview back instead of leaving the result implicit.",
|
|
3089
3094
|
"Route to the dedicated life-force path once the lane is clear."
|
|
3090
3095
|
]
|
|
3091
3096
|
},
|
|
3092
3097
|
{
|
|
3093
3098
|
focus: "workbench",
|
|
3094
|
-
openingQuestion: "
|
|
3099
|
+
openingQuestion: "What are you trying to inspect, change, run, or publish through Workbench?",
|
|
3095
3100
|
coachingGoal: "Clarify whether the user wants flow discovery, editing, execution, run history, published outputs, or node-level inspection before using the dedicated workbench route family.",
|
|
3096
3101
|
askSequence: [
|
|
3097
3102
|
"Ask whether the job is flow discovery, one flow edit, execution, run history, published output, node-level inspection, or latest-node-output lookup.",
|
|
@@ -3099,6 +3104,7 @@ const AGENT_ONBOARDING_ENTITY_CONVERSATION_PLAYBOOKS = [
|
|
|
3099
3104
|
"Ask whether they need the flow contract, a run result, a published output, or a node result.",
|
|
3100
3105
|
"Ask what the user is trying to learn, repair, or publish through that flow.",
|
|
3101
3106
|
"If the user already named the flow and action clearly, skip the meta lane question and ask only for the missing run, node, or output scope.",
|
|
3107
|
+
"If the user is still shaping a payload or edit, prefer flow detail or box catalog reads before asking for structured inputs.",
|
|
3102
3108
|
"Prefer flow detail or published-output reads for stable contracts, and use run or node-result routes only when the user is asking about execution history or debugging.",
|
|
3103
3109
|
"Route to the dedicated workbench route family once the execution lane is clear."
|
|
3104
3110
|
]
|
|
@@ -4065,25 +4071,32 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4065
4071
|
allTime: "/api/v1/movement/all-time",
|
|
4066
4072
|
timeline: "/api/v1/movement/timeline",
|
|
4067
4073
|
places: "/api/v1/movement/places",
|
|
4074
|
+
boxDetail: "/api/v1/movement/boxes/:id",
|
|
4068
4075
|
tripDetail: "/api/v1/movement/trips/:id",
|
|
4069
4076
|
selection: "/api/v1/movement/selection",
|
|
4070
4077
|
settings: "/api/v1/movement/settings"
|
|
4071
4078
|
},
|
|
4072
4079
|
writeRoutes: {
|
|
4080
|
+
settingsUpdate: "/api/v1/movement/settings",
|
|
4073
4081
|
placeCreate: "/api/v1/movement/places",
|
|
4074
4082
|
placeUpdate: "/api/v1/movement/places/:id",
|
|
4075
4083
|
userBoxCreate: "/api/v1/movement/user-boxes",
|
|
4076
4084
|
userBoxPreflight: "/api/v1/movement/user-boxes/preflight",
|
|
4077
4085
|
userBoxUpdate: "/api/v1/movement/user-boxes/:id",
|
|
4086
|
+
userBoxDelete: "/api/v1/movement/user-boxes/:id",
|
|
4078
4087
|
automaticBoxInvalidate: "/api/v1/movement/automatic-boxes/:id/invalidate",
|
|
4079
4088
|
stayUpdate: "/api/v1/movement/stays/:id",
|
|
4089
|
+
stayDelete: "/api/v1/movement/stays/:id",
|
|
4080
4090
|
tripUpdate: "/api/v1/movement/trips/:id",
|
|
4081
|
-
|
|
4091
|
+
tripDelete: "/api/v1/movement/trips/:id",
|
|
4092
|
+
tripPointUpdate: "/api/v1/movement/trips/:id/points/:pointId",
|
|
4093
|
+
tripPointDelete: "/api/v1/movement/trips/:id/points/:pointId"
|
|
4082
4094
|
},
|
|
4083
4095
|
notes: [
|
|
4084
4096
|
"Movement is not a normal batch CRUD entity family. It is a dedicated record of stays and trips: a stay means the user remained in the same place for a span of time, and a trip means they traveled between places.",
|
|
4085
4097
|
"Use /api/v1/movement/day, /month, /all-time, /timeline, or /selection when the user wants behavioral answers such as how long they stayed at home, when they traveled, which places dominated a period, or what happened across a selected span.",
|
|
4086
4098
|
"Use the movement write routes when the user wants to add a place or manual overlay, update a specific stay or trip, repair one recorded movement span, or attach movement context to another Forge record. If the user is filling a missing-data gap, the usual write path is a user-defined overlay box rather than a raw stay or trip patch.",
|
|
4099
|
+
"If the user is revising or removing an existing correction, first identify whether the saved object is a user-defined box, automatic box, recorded stay, recorded trip, or trip point so the repair or delete path stays truthful.",
|
|
4087
4100
|
"For an explicit statement like 'that missing block was me staying home', do not reopen broad intake. Preflight only if timing overlap is unclear, then create a user-defined `stay` box for that interval and read the updated timeline back."
|
|
4088
4101
|
]
|
|
4089
4102
|
},
|
|
@@ -4101,6 +4114,7 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4101
4114
|
"Life Force is a focused domain surface, not a batch CRUD entity type.",
|
|
4102
4115
|
"Use GET /api/v1/life-force for the current overview payload with stats, drains, recommendations, and current-curve state.",
|
|
4103
4116
|
"Patch the profile only for durable personal settings, update weekday templates only for the curve itself, and post fatigue signals for real-time tired or recovered observations.",
|
|
4117
|
+
"If the user is asking what changed after a profile, template, or fatigue write, read the overview back so the effect stays visible.",
|
|
4104
4118
|
"If the user already knows they want a profile change, weekday-template edit, or right-now fatigue signal, skip the broad lane question and ask only for the missing weekday, profile field, or signal detail."
|
|
4105
4119
|
]
|
|
4106
4120
|
},
|
|
@@ -4129,6 +4143,7 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4129
4143
|
notes: [
|
|
4130
4144
|
"Workbench is a dedicated execution surface, not a batch CRUD entity family.",
|
|
4131
4145
|
"Use the flow routes when the agent needs stable public input contracts, published outputs, node-level results, or reusable execution history.",
|
|
4146
|
+
"If the user is still figuring out inputs or editable structure, read flow detail or box catalog before asking them to author a payload from memory.",
|
|
4132
4147
|
"Prefer the dedicated output and node-result routes over reverse-engineering raw traces.",
|
|
4133
4148
|
"If the user already named the flow and wants one output or one run, skip the broad lane question and ask only for the missing run, node, or output scope."
|
|
4134
4149
|
]
|
|
@@ -4330,8 +4345,8 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4330
4345
|
saveSuggestionPlacement: "end_of_message",
|
|
4331
4346
|
saveSuggestionTone: "gentle_optional",
|
|
4332
4347
|
maxQuestionsPerTurn: 1,
|
|
4333
|
-
psycheExplorationRule: "When a Psyche entity needs understanding first, begin with one exploratory question before any working formulation, replacement belief, suggested title, or save pitch. Keep the opening reflection to one or two short sentences, stay in plain prose instead of bullets or numbered lists, keep that first reply short, do not mention Forge search or save structure yet, avoid colons or list-shaped phrasing, prefer what/when/how over why until the experience is grounded, wait for the user's answer before offering a fuller formulation, ask permission before moving from charged exploration into naming or challenge when needed, do not widen into adjacent entities until the current one has a working sentence the user recognizes, and once the lived experience is coherent stop deepening and help the user name it cleanly. If the user accepts the wording, move toward the save instead of reopening deeper exploration.",
|
|
4334
|
-
specializedSurfaceRule: "For Movement, Life Force, and Workbench, clarify the lane first, then name the dedicated route family in plain language and do not guess at a generic CRUD path. When the user already named a precise correction or review target, confirm only the route-selecting detail that is still missing. The canonical runtime routes stay under /api/v1/*, and the OpenClaw HTTP mirror exposes the same families under /forge/v1/movement, /forge/v1/life-force, and /forge/v1/workbench.",
|
|
4348
|
+
psycheExplorationRule: "When a Psyche entity needs understanding first, begin with one exploratory question before any working formulation, replacement belief, suggested title, or save pitch. Keep the opening reflection to one or two short sentences, stay in plain prose instead of bullets or numbered lists, keep that first reply short, do not mention Forge search or save structure yet, avoid colons or list-shaped phrasing, prefer what/when/how over why until the experience is grounded, wait for the user's answer before offering a fuller formulation, ask permission before moving from charged exploration into naming or challenge when needed, do not widen into adjacent entities until the current one has a working sentence the user recognizes, and once the lived experience is coherent stop deepening and help the user name it cleanly. When the user is updating a Psyche record because of one fresh episode, anchor in that episode before renaming the durable formulation. If the user accepts the wording, move toward the save instead of reopening deeper exploration.",
|
|
4349
|
+
specializedSurfaceRule: "For Movement, Life Force, and Workbench, clarify the lane first, then name the dedicated route family in plain language and do not guess at a generic CRUD path. When the user already named a precise correction or review target, confirm only the route-selecting detail that is still missing. After a concrete specialized-surface correction, read the relevant specialized view back when the user is trying to understand the result rather than just store it. The canonical runtime routes stay under /api/v1/*, and the OpenClaw HTTP mirror exposes the same families under /forge/v1/movement, /forge/v1/life-force, and /forge/v1/workbench.",
|
|
4335
4350
|
reviewShortcutRule: "When the user is reviewing or correcting an existing record, narrow the saved object, timeframe, or route family first. Do not reopen the whole intake unless the user is actually redefining the record.",
|
|
4336
4351
|
readModelWriteRule: "Self-observation is note-backed and should be written through observed notes with frontmatter.observedAt. Sleep and workout sessions stay on batch CRUD by default; use the reflective review helpers only when enriching one already-known record after review.",
|
|
4337
4352
|
psycheOpeningQuestionRule: "Prefer a concrete opening question tied to the entity: ask when the value mattered, what happened the last time the pattern appeared, what cue or body signal came first before the behavior, what the belief starts saying about self or outcome, what feels most at risk inside the mode, what the part is trying to get the user to do or stop doing, or where the shift began in the incident. Reflect briefly before the question, choose one follow-up lane at a time, say what is becoming clearer before the next deeper question, and if several Psyche entities are visible hold the adjacent ones lightly until the main container is clear.",
|
|
@@ -5868,9 +5883,20 @@ export async function buildServer(options = {}) {
|
|
|
5868
5883
|
};
|
|
5869
5884
|
});
|
|
5870
5885
|
app.patch("/api/v1/mobile/movement/stays/:id", async (request, reply) => {
|
|
5871
|
-
|
|
5886
|
+
const parsed = movementMobileStayPatchSchema.parse(request.body ?? {});
|
|
5887
|
+
const pairing = requireValidPairing(parsed.sessionId, parsed.pairingToken);
|
|
5888
|
+
const { id } = request.params;
|
|
5889
|
+
const stay = updateMovementStay(id, parsed.patch, {
|
|
5890
|
+
actor: "Forge Companion",
|
|
5891
|
+
source: "system"
|
|
5892
|
+
}, { userId: pairing.user_id });
|
|
5893
|
+
if (!stay) {
|
|
5894
|
+
reply.code(404);
|
|
5895
|
+
return { error: "Movement stay not found" };
|
|
5896
|
+
}
|
|
5872
5897
|
return {
|
|
5873
|
-
|
|
5898
|
+
stay,
|
|
5899
|
+
place: stay.place
|
|
5874
5900
|
};
|
|
5875
5901
|
});
|
|
5876
5902
|
app.patch("/api/v1/mobile/movement/trips/:id", async (request, reply) => {
|
|
@@ -130,7 +130,7 @@ const linkedPersonSchema = z.object({
|
|
|
130
130
|
label: z.string().trim().min(1)
|
|
131
131
|
});
|
|
132
132
|
const movementPlaceInputSchema = z.object({
|
|
133
|
-
externalUid: z.string().trim().
|
|
133
|
+
externalUid: z.string().trim().default(""),
|
|
134
134
|
label: z.string().trim().min(1),
|
|
135
135
|
aliases: z.array(z.string().trim()).default([]),
|
|
136
136
|
latitude: z.number().finite(),
|
|
@@ -1011,6 +1011,61 @@ function mapMovementPlace(row) {
|
|
|
1011
1011
|
: null
|
|
1012
1012
|
};
|
|
1013
1013
|
}
|
|
1014
|
+
function readMovementPlaceLearningState(row) {
|
|
1015
|
+
const metadata = safeJsonParse(row.metadata_json, {});
|
|
1016
|
+
const sampleCount = Number(metadata.distributionSampleCount);
|
|
1017
|
+
const averageLatitude = Number(metadata.distributionAverageLatitude);
|
|
1018
|
+
const averageLongitude = Number(metadata.distributionAverageLongitude);
|
|
1019
|
+
const maxDistanceMeters = Number(metadata.distributionMaxDistanceMeters);
|
|
1020
|
+
return {
|
|
1021
|
+
sampleCount: Number.isFinite(sampleCount) && sampleCount >= 1 ? Math.floor(sampleCount) : 1,
|
|
1022
|
+
averageLatitude: Number.isFinite(averageLatitude) ? averageLatitude : row.latitude,
|
|
1023
|
+
averageLongitude: Number.isFinite(averageLongitude) ? averageLongitude : row.longitude,
|
|
1024
|
+
maxDistanceMeters: Number.isFinite(maxDistanceMeters) && maxDistanceMeters >= 0
|
|
1025
|
+
? maxDistanceMeters
|
|
1026
|
+
: 0
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
1029
|
+
function learnMovementPlaceObservation(input) {
|
|
1030
|
+
const existing = getDatabase()
|
|
1031
|
+
.prepare(`SELECT *
|
|
1032
|
+
FROM movement_places
|
|
1033
|
+
WHERE id = ?`)
|
|
1034
|
+
.get(input.placeId);
|
|
1035
|
+
if (!existing) {
|
|
1036
|
+
return null;
|
|
1037
|
+
}
|
|
1038
|
+
const metadata = safeJsonParse(existing.metadata_json, {});
|
|
1039
|
+
const learning = readMovementPlaceLearningState(existing);
|
|
1040
|
+
const nextSampleCount = learning.sampleCount + 1;
|
|
1041
|
+
const nextAverageLatitude = (learning.averageLatitude * learning.sampleCount + input.observation.latitude) /
|
|
1042
|
+
nextSampleCount;
|
|
1043
|
+
const nextAverageLongitude = (learning.averageLongitude * learning.sampleCount + input.observation.longitude) /
|
|
1044
|
+
nextSampleCount;
|
|
1045
|
+
const observationDistance = haversineDistanceMeters({ latitude: nextAverageLatitude, longitude: nextAverageLongitude }, input.observation);
|
|
1046
|
+
const nextMaxDistanceMeters = Math.max(learning.maxDistanceMeters, observationDistance);
|
|
1047
|
+
const nextRadiusMeters = Math.min(2000, Math.max(existing.radius_meters, Math.ceil(nextMaxDistanceMeters + 25)));
|
|
1048
|
+
const nextMetadata = {
|
|
1049
|
+
...metadata,
|
|
1050
|
+
distributionSampleCount: String(nextSampleCount),
|
|
1051
|
+
distributionAverageLatitude: nextAverageLatitude.toFixed(6),
|
|
1052
|
+
distributionAverageLongitude: nextAverageLongitude.toFixed(6),
|
|
1053
|
+
distributionMaxDistanceMeters: nextMaxDistanceMeters.toFixed(1),
|
|
1054
|
+
distributionLastObservedAt: nowIso()
|
|
1055
|
+
};
|
|
1056
|
+
getDatabase()
|
|
1057
|
+
.prepare(`UPDATE movement_places
|
|
1058
|
+
SET latitude = ?,
|
|
1059
|
+
longitude = ?,
|
|
1060
|
+
radius_meters = ?,
|
|
1061
|
+
metadata_json = ?,
|
|
1062
|
+
updated_at = ?
|
|
1063
|
+
WHERE id = ?`)
|
|
1064
|
+
.run(nextAverageLatitude, nextAverageLongitude, nextRadiusMeters, JSON.stringify(nextMetadata), nowIso(), input.placeId);
|
|
1065
|
+
return mapMovementPlace(getDatabase()
|
|
1066
|
+
.prepare(`SELECT * FROM movement_places WHERE id = ?`)
|
|
1067
|
+
.get(input.placeId));
|
|
1068
|
+
}
|
|
1014
1069
|
function mapMovementStay(row, placesById) {
|
|
1015
1070
|
const note = row.published_note_id ? getNoteById(row.published_note_id) : null;
|
|
1016
1071
|
const metrics = safeJsonParse(row.metrics_json, {});
|
|
@@ -1637,6 +1692,9 @@ function upsertMovementSettings(userId, input) {
|
|
|
1637
1692
|
}
|
|
1638
1693
|
function upsertMovementPlaceInternal(input) {
|
|
1639
1694
|
const parsed = movementPlaceInputSchema.parse(input.place);
|
|
1695
|
+
const externalUid = parsed.externalUid.trim().length > 0
|
|
1696
|
+
? parsed.externalUid.trim()
|
|
1697
|
+
: `movement-place-${randomUUID().replaceAll("-", "").slice(0, 20)}`;
|
|
1640
1698
|
const now = nowIso();
|
|
1641
1699
|
const existing = input.id && input.id.trim().length > 0
|
|
1642
1700
|
? getDatabase()
|
|
@@ -1644,14 +1702,14 @@ function upsertMovementPlaceInternal(input) {
|
|
|
1644
1702
|
FROM movement_places
|
|
1645
1703
|
WHERE id = ?`)
|
|
1646
1704
|
.get(input.id)
|
|
1647
|
-
:
|
|
1705
|
+
: externalUid.length > 0
|
|
1648
1706
|
? getDatabase()
|
|
1649
1707
|
.prepare(`SELECT *
|
|
1650
1708
|
FROM movement_places
|
|
1651
1709
|
WHERE user_id = ?
|
|
1652
1710
|
AND source = ?
|
|
1653
1711
|
AND external_uid = ?`)
|
|
1654
|
-
.get(input.userId, input.source,
|
|
1712
|
+
.get(input.userId, input.source, externalUid)
|
|
1655
1713
|
: undefined;
|
|
1656
1714
|
const id = existing?.id ?? input.id ?? `mpl_${randomUUID().replaceAll("-", "").slice(0, 10)}`;
|
|
1657
1715
|
getDatabase()
|
|
@@ -1677,7 +1735,7 @@ function upsertMovementPlaceInternal(input) {
|
|
|
1677
1735
|
metadata_json = excluded.metadata_json,
|
|
1678
1736
|
source = excluded.source,
|
|
1679
1737
|
updated_at = excluded.updated_at`)
|
|
1680
|
-
.run(id,
|
|
1738
|
+
.run(id, externalUid, input.userId, parsed.label, JSON.stringify(uniqStrings(parsed.aliases)), parsed.latitude, parsed.longitude, parsed.radiusMeters, JSON.stringify(canonicalizeMovementCategoryTags(parsed.categoryTags)), parsed.visibility, parsed.wikiNoteId, JSON.stringify(parsed.linkedEntities), JSON.stringify(parsed.linkedPeople), JSON.stringify(parsed.metadata), input.source, existing?.created_at ?? now, now);
|
|
1681
1739
|
syncPlaceWikiMetadata(id);
|
|
1682
1740
|
return mapMovementPlace(getDatabase()
|
|
1683
1741
|
.prepare(`SELECT * FROM movement_places WHERE id = ?`)
|
|
@@ -3868,6 +3926,8 @@ export function updateMovementStay(stayId, patch, context, options = {}) {
|
|
|
3868
3926
|
...safeJsonParse(existing.metadata_json, {}),
|
|
3869
3927
|
...(parsed.metadata ?? {})
|
|
3870
3928
|
};
|
|
3929
|
+
const shouldLearnPlaceObservation = resolvedPlace !== null &&
|
|
3930
|
+
(hasOwn(parsed, "placeId") || hasOwn(parsed, "placeExternalUid"));
|
|
3871
3931
|
getDatabase()
|
|
3872
3932
|
.prepare(`UPDATE movement_stays
|
|
3873
3933
|
SET place_id = ?,
|
|
@@ -3886,6 +3946,17 @@ export function updateMovementStay(stayId, patch, context, options = {}) {
|
|
|
3886
3946
|
WHERE id = ?`)
|
|
3887
3947
|
.run(resolvedPlace?.id ?? null, parsed.label ?? parsed.placeLabel ?? existing.label, parsed.status ?? existing.status, parsed.classification ?? existing.classification, startedAt, endedAt, parsed.centerLatitude ?? existing.center_latitude, parsed.centerLongitude ?? existing.center_longitude, parsed.radiusMeters ?? existing.radius_meters, parsed.sampleCount ?? existing.sample_count, JSON.stringify(metrics), JSON.stringify(metadata), nowIso(), stayId);
|
|
3888
3948
|
reconcileMovementOverlapValidation(existing.user_id);
|
|
3949
|
+
let learnedPlace = resolvedPlace ? mapMovementPlace(resolvedPlace) : null;
|
|
3950
|
+
if (resolvedPlace && shouldLearnPlaceObservation) {
|
|
3951
|
+
learnedPlace =
|
|
3952
|
+
learnMovementPlaceObservation({
|
|
3953
|
+
placeId: resolvedPlace.id,
|
|
3954
|
+
observation: {
|
|
3955
|
+
latitude: parsed.centerLatitude ?? existing.center_latitude,
|
|
3956
|
+
longitude: parsed.centerLongitude ?? existing.center_longitude
|
|
3957
|
+
}
|
|
3958
|
+
}) ?? learnedPlace;
|
|
3959
|
+
}
|
|
3889
3960
|
const places = listMovementPlaceRows([existing.user_id]).map(mapMovementPlace);
|
|
3890
3961
|
const placesById = new Map(places.map((place) => [place.id, place]));
|
|
3891
3962
|
const updated = mapMovementStay(getDatabase()
|
|
@@ -3906,7 +3977,10 @@ export function updateMovementStay(stayId, patch, context, options = {}) {
|
|
|
3906
3977
|
durationSeconds: updated.durationSeconds
|
|
3907
3978
|
}
|
|
3908
3979
|
});
|
|
3909
|
-
return
|
|
3980
|
+
return {
|
|
3981
|
+
...updated,
|
|
3982
|
+
place: learnedPlace && updated.placeId === learnedPlace.id ? learnedPlace : updated.place
|
|
3983
|
+
};
|
|
3910
3984
|
}
|
|
3911
3985
|
export function updateMovementTrip(tripId, patch, context, options = {}) {
|
|
3912
3986
|
const existing = getDatabase()
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -141,6 +141,7 @@ Psyche interview rule:
|
|
|
141
141
|
- Sound professionally warm and therapist-like: grounded, accurate, reflective, and intentional, not clinical, vague, or lecture-like.
|
|
142
142
|
- After the first real answer, choose one follow-up lane at a time: situation, sequence, meaning, protection, cost, longing/value, or tentative name.
|
|
143
143
|
- For Psyche updates, start with what feels newly true, newly visible, or newly inaccurate, then ask what should stay true before changing the formulation.
|
|
144
|
+
- If a fresh episode is what made a Psyche update visible, anchor in that episode before renaming the durable belief, pattern, mode, or value.
|
|
144
145
|
- If the user says they want help understanding a Psyche issue before saving it, ask one orienting question first instead of jumping straight into a full interpretation, diagnosis-like label, save suggestion, replacement belief, or suggested title.
|
|
145
146
|
- In that first exploratory turn, keep the reflection to one or two short sentences, avoid numbered lists or schema dumps, and wait for the user's answer before offering a fuller formulation.
|
|
146
147
|
- In that first exploratory turn, stay in plain prose, end with one question, and do not mention Forge fields or save formatting yet unless the user interrupts to save immediately.
|
|
@@ -386,6 +387,7 @@ Use the dedicated domain routes for specialized surfaces that are not simple bat
|
|
|
386
387
|
`/api/v1/workbench/flows/:id/output` for published outputs, and the run/node routes
|
|
387
388
|
under `/api/v1/workbench/flows/:id` for run history and node-level inspection.
|
|
388
389
|
- If you are unsure which specialized route family applies, check `forge_get_agent_onboarding` and use its `entityRouteModel.specializedDomainSurfaces` section before guessing.
|
|
390
|
+
- After a concrete Movement, Life Force, or Workbench correction, read the relevant specialized view back when the user is trying to understand the result rather than only store it.
|
|
389
391
|
|
|
390
392
|
Use live work tools for `task_run`:
|
|
391
393
|
`forge_log_work`, `forge_start_task_run`, `forge_heartbeat_task_run`, `forge_focus_task_run`, `forge_complete_task_run`, `forge_release_task_run`
|
|
@@ -1016,6 +1016,11 @@ Direct action rules:
|
|
|
1016
1016
|
traveled.
|
|
1017
1017
|
- Use raw `PATCH /api/v1/movement/stays/:id` or `/api/v1/movement/trips/:id` only for
|
|
1018
1018
|
editing an already-recorded stay or trip, not for filling a missing span.
|
|
1019
|
+
- If the user wants to undo or remove one manual overlay, delete the saved
|
|
1020
|
+
user-defined box instead of patching a recorded stay or trip.
|
|
1021
|
+
- If the user wants to inspect one already-saved movement correction before editing
|
|
1022
|
+
it, read the box detail first so the follow-up write stays grounded in the saved
|
|
1023
|
+
object.
|
|
1019
1024
|
- When the user has already given the real answer, for example "I stayed home during
|
|
1020
1025
|
that missing block", do not ask a broad review question again. Confirm only the
|
|
1021
1026
|
interval or place if that is still ambiguous, then act.
|
|
@@ -1045,14 +1050,20 @@ Lane-to-route map:
|
|
|
1045
1050
|
`/api/v1/movement/places` or `/api/v1/movement/places/:id`
|
|
1046
1051
|
- inspect one trip:
|
|
1047
1052
|
`/api/v1/movement/trips/:id`
|
|
1053
|
+
- inspect one saved movement box before repairing it:
|
|
1054
|
+
`/api/v1/movement/boxes/:id`
|
|
1048
1055
|
- fill a missing span:
|
|
1049
1056
|
`/api/v1/movement/user-boxes/preflight` then `/api/v1/movement/user-boxes`
|
|
1050
1057
|
- repair or revise one saved overlay:
|
|
1051
1058
|
`/api/v1/movement/user-boxes/:id`
|
|
1059
|
+
- delete one saved overlay:
|
|
1060
|
+
`DELETE /api/v1/movement/user-boxes/:id`
|
|
1052
1061
|
- repair one recorded automatic box:
|
|
1053
1062
|
`/api/v1/movement/automatic-boxes/:id/invalidate`
|
|
1054
1063
|
- edit an already-recorded stay, trip, or trip point:
|
|
1055
1064
|
`/api/v1/movement/stays/:id`, `/api/v1/movement/trips/:id`, or `/api/v1/movement/trips/:id/points/:pointId`
|
|
1065
|
+
- delete an already-recorded stay, trip, or trip point:
|
|
1066
|
+
`DELETE /api/v1/movement/stays/:id`, `DELETE /api/v1/movement/trips/:id`, or `DELETE /api/v1/movement/trips/:id/points/:pointId`
|
|
1056
1067
|
|
|
1057
1068
|
Ready to act when:
|
|
1058
1069
|
|
|
@@ -1063,7 +1074,7 @@ Ready to act when:
|
|
|
1063
1074
|
|
|
1064
1075
|
Preferred opening question:
|
|
1065
1076
|
|
|
1066
|
-
- "What are you trying to
|
|
1077
|
+
- "What are you trying to understand, correct, or preserve about where you stayed and traveled?"
|
|
1067
1078
|
|
|
1068
1079
|
## Life Force
|
|
1069
1080
|
|
|
@@ -1109,6 +1120,8 @@ Direct action rules:
|
|
|
1109
1120
|
template instead of editing the profile.
|
|
1110
1121
|
- If the user is describing right-now depletion or recovery, post a fatigue signal and
|
|
1111
1122
|
then read the overview back if they want to see the updated picture.
|
|
1123
|
+
- After a profile or weekday-template change, read the overview back when the user is
|
|
1124
|
+
trying to understand the practical impact of the change, not just store it silently.
|
|
1112
1125
|
|
|
1113
1126
|
Ready to act when:
|
|
1114
1127
|
|
|
@@ -1118,7 +1131,7 @@ Ready to act when:
|
|
|
1118
1131
|
|
|
1119
1132
|
Preferred opening question:
|
|
1120
1133
|
|
|
1121
|
-
- "What feels most off, important, or worth
|
|
1134
|
+
- "What feels most off, important, or worth understanding in your energy picture right now?"
|
|
1122
1135
|
|
|
1123
1136
|
## Workbench
|
|
1124
1137
|
|
|
@@ -1153,6 +1166,8 @@ Lane-to-route map:
|
|
|
1153
1166
|
`/api/v1/workbench/flows/:id/run`
|
|
1154
1167
|
- run from a payload-first contract:
|
|
1155
1168
|
`/api/v1/workbench/run`
|
|
1169
|
+
- send one follow-up message into a saved flow chat:
|
|
1170
|
+
`/api/v1/workbench/flows/:id/chat`
|
|
1156
1171
|
- inspect published output or run history:
|
|
1157
1172
|
`/api/v1/workbench/flows/:id/output` or `/api/v1/workbench/flows/:id/runs`
|
|
1158
1173
|
- inspect one run or node result:
|
|
@@ -1173,6 +1188,8 @@ Direct action rules:
|
|
|
1173
1188
|
`/api/v1/workbench/run`.
|
|
1174
1189
|
- If the user wants one node's latest successful output, do not browse old runs first
|
|
1175
1190
|
unless they explicitly want historical debugging.
|
|
1191
|
+
- If the user wants to understand what inputs a flow can accept before editing or
|
|
1192
|
+
running it, read the box catalog or flow detail before asking for a payload.
|
|
1176
1193
|
|
|
1177
1194
|
Ready to act when:
|
|
1178
1195
|
|
|
@@ -1182,7 +1199,7 @@ Ready to act when:
|
|
|
1182
1199
|
|
|
1183
1200
|
Preferred opening question:
|
|
1184
1201
|
|
|
1185
|
-
- "What are you trying to inspect
|
|
1202
|
+
- "What are you trying to inspect, change, run, or publish through Workbench?"
|
|
1186
1203
|
|
|
1187
1204
|
## Preference Catalog
|
|
1188
1205
|
|
|
@@ -350,6 +350,9 @@ If the entity is already clear:
|
|
|
350
350
|
|
|
351
351
|
- reflect briefly
|
|
352
352
|
- name the core meaning in the user's language
|
|
353
|
+
- if the user already gave a serviceable belief sentence, mode name, value phrase, or
|
|
354
|
+
pattern title, stay inside that wording long enough to reflect the live stake before
|
|
355
|
+
you ask for the one missing structural detail
|
|
353
356
|
- keep the user's own wording when it is already serviceable and only refine one
|
|
354
357
|
phrase if needed
|
|
355
358
|
- ask only for the one missing structural detail
|
|
@@ -376,6 +379,8 @@ If the entity is not yet clear:
|
|
|
376
379
|
replacing it with a more polished label unless they ask for help wording it.
|
|
377
380
|
- When the user says the current wording misses, say what seems newly true before you
|
|
378
381
|
ask whether the old name still fits.
|
|
382
|
+
- If a recent charged episode is what made the update visible, anchor in that episode
|
|
383
|
+
before you rename the durable belief, pattern, mode, or value.
|
|
379
384
|
- If another belief, value, pattern, mode, or note becomes visible, name it gently but
|
|
380
385
|
do not switch containers unless the user wants to.
|
|
381
386
|
|
|
@@ -386,9 +391,11 @@ from scratch.
|
|
|
386
391
|
|
|
387
392
|
1. Ask what feels newly true, newly visible, or newly inaccurate.
|
|
388
393
|
2. Ask what still feels essentially right and should not be lost.
|
|
389
|
-
3.
|
|
390
|
-
|
|
391
|
-
|
|
394
|
+
3. If the update was triggered by one recent charged episode, anchor in that episode
|
|
395
|
+
before you re-check the durable formulation.
|
|
396
|
+
4. Re-check the name only if the old wording no longer fits the lived experience.
|
|
397
|
+
5. Ask for one concrete recent example if the update is abstract or sweeping.
|
|
398
|
+
6. Then change only the parts the new understanding actually affects.
|
|
392
399
|
|
|
393
400
|
If the update is mostly about wording, offer one revised sentence yourself and ask
|
|
394
401
|
whether it lands more accurately before you reopen the whole exploration.
|