forge-openclaw-plugin 0.2.59 → 0.2.61
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 +93 -46
- package/dist/assets/{board-BAxNp060.js → board-DThHV1D8.js} +1 -2
- package/dist/assets/index-7gvVCqnV.css +1 -0
- package/dist/assets/index-_Cn6Prym.js +90 -0
- package/dist/assets/knowledge-graph-layout.worker-DRvzPxhP.js +0 -1
- package/dist/assets/{motion-B9BeeSmV.js → motion-BtTJtHCw.js} +1 -2
- package/dist/assets/{table-kY1tUKX5.js → table-Bnw6pcwN.js} +1 -2
- package/dist/assets/{ui-FaWfAb5Q.js → ui-CnVxFkj0.js} +1 -2
- package/dist/assets/{vendor-CUxVKN94.js → vendor-BgZ3YrRd.js} +212 -208
- package/dist/gamification-previews/dark-fantasy-item-trophy-tasks-anvil-marathon.webp +0 -0
- package/dist/gamification-previews/dark-fantasy-item-trophy-xp-levels-the-first-heat.webp +0 -0
- package/dist/gamification-previews/dark-fantasy-item-unlock-streaks-molten-crown-fire.webp +0 -0
- package/dist/gamification-previews/dark-fantasy-mascot.webp +0 -0
- package/dist/gamification-previews/dramatic-smithie-item-trophy-tasks-anvil-marathon.webp +0 -0
- package/dist/gamification-previews/dramatic-smithie-item-trophy-xp-levels-the-first-heat.webp +0 -0
- package/dist/gamification-previews/dramatic-smithie-item-unlock-streaks-molten-crown-fire.webp +0 -0
- package/dist/gamification-previews/dramatic-smithie-mascot.webp +0 -0
- package/dist/gamification-previews/mind-locksmith-item-trophy-tasks-anvil-marathon.webp +0 -0
- package/dist/gamification-previews/mind-locksmith-item-trophy-xp-levels-the-first-heat.webp +0 -0
- package/dist/gamification-previews/mind-locksmith-item-unlock-streaks-molten-crown-fire.webp +0 -0
- package/dist/gamification-previews/mind-locksmith-mascot.webp +0 -0
- package/dist/index.html +7 -7
- package/dist/openclaw/parity.js +27 -0
- package/dist/openclaw/plugin-entry-shared.js +2 -2
- package/dist/openclaw/plugin-sdk-types.d.ts +2 -1
- package/dist/openclaw/routes.d.ts +4 -0
- package/dist/openclaw/routes.js +112 -3
- package/dist/openclaw/tools.js +32 -4
- package/dist/server/server/migrations/058_gamification_theme_preference.sql +1 -1
- package/dist/server/server/migrations/059_data_backup_retention.sql +2 -0
- package/dist/server/server/src/app.js +152 -43
- package/dist/server/server/src/data-management-types.js +2 -0
- package/dist/server/server/src/health.js +40 -0
- package/dist/server/server/src/openapi.js +398 -7
- package/dist/server/server/src/repositories/rewards.js +60 -0
- package/dist/server/server/src/repositories/settings.js +1 -1
- package/dist/server/server/src/services/data-management.js +32 -2
- package/dist/server/server/src/services/doctor.js +762 -0
- package/dist/server/server/src/services/gamification-assets.js +231 -0
- package/dist/server/server/src/services/gamification.js +75 -3
- package/dist/server/server/src/types.js +1 -1
- package/dist/server/server/src/web.js +7 -104
- package/dist/server/src/lib/api.js +18 -0
- package/dist/server/src/lib/gamification-catalog.js +1 -1
- package/dist/server/src/lib/schemas.js +1 -1
- package/openclaw.plugin.json +85 -3
- package/package.json +8 -4
- package/server/migrations/058_gamification_theme_preference.sql +1 -1
- package/server/migrations/059_data_backup_retention.sql +2 -0
- package/skills/forge-openclaw/SKILL.md +38 -19
- package/skills/forge-openclaw/entity_conversation_playbooks.md +66 -8
- package/skills/forge-openclaw/psyche_entity_playbooks.md +23 -0
- package/dist/assets/board-BAxNp060.js.map +0 -1
- package/dist/assets/index-B5Yt4i07.css +0 -1
- package/dist/assets/index-NZwTuYPs.js +0 -91
- package/dist/assets/index-NZwTuYPs.js.map +0 -1
- package/dist/assets/knowledge-graph-layout.worker-DRvzPxhP.js.map +0 -1
- package/dist/assets/motion-B9BeeSmV.js.map +0 -1
- package/dist/assets/table-kY1tUKX5.js.map +0 -1
- package/dist/assets/ui-FaWfAb5Q.js.map +0 -1
- package/dist/assets/vendor-CUxVKN94.js.map +0 -1
- package/dist/gamification/sprites.zip +0 -0
|
@@ -26,6 +26,7 @@ import { createProject, updateProject } from "./repositories/projects.js";
|
|
|
26
26
|
import { createPreferenceCatalog, createPreferenceCatalogItem, createPreferenceContext, createPreferenceItem, createPreferenceItemFromEntity, deletePreferenceCatalog, deletePreferenceCatalogItem, deletePreferenceContext, deletePreferenceItem, getPreferenceCatalogById, getPreferenceCatalogItemById, getPreferenceContextById, getPreferenceItemById, getPreferenceWorkspace, listPreferenceCatalogItems, listPreferenceCatalogs, listPreferenceContexts, listPreferenceItems, mergePreferenceContexts, startPreferenceGame, submitAbsoluteSignal, submitPairwiseJudgment, updatePreferenceCatalog, updatePreferenceCatalogItem, updatePreferenceContext, updatePreferenceItem, updatePreferenceScore } from "./repositories/preferences.js";
|
|
27
27
|
import { createStrategy, getStrategyById, listStrategies, updateStrategy } from "./repositories/strategies.js";
|
|
28
28
|
import { buildKnowledgeGraph, buildKnowledgeGraphFocus } from "./services/knowledge-graph.js";
|
|
29
|
+
import { applyForgeDoctorFixes, buildForgeDoctorReport } from "./services/doctor.js";
|
|
29
30
|
import { createManualRewardGrant, getRewardRuleById, listRewardLedger, listRewardRules, recordWorkAdjustmentReward, recordSessionEvent, updateRewardRule } from "./repositories/rewards.js";
|
|
30
31
|
import { markGamificationCelebrationSeen } from "./repositories/gamification.js";
|
|
31
32
|
import { getSettingsFileStatus, listAgentIdentities, getSettings, isPsycheAuthRequired, mirrorSettingsFileFromCurrentState, updateSettings, verifyAgentToken } from "./repositories/settings.js";
|
|
@@ -40,6 +41,7 @@ import { createCalendarEvent, createTaskTimebox, createWorkBlockTemplate, delete
|
|
|
40
41
|
import { getDashboard } from "./services/dashboard.js";
|
|
41
42
|
import { getOverviewContext, getRiskContext, getTodayContext } from "./services/context.js";
|
|
42
43
|
import { buildGamificationCatalogPayload, buildGamificationOverview, buildGamificationProfile, buildXpMetricsPayloadModel, LockedGamificationCosmeticError, updateGamificationEquipmentSelection } from "./services/gamification.js";
|
|
44
|
+
import { getGamificationAssetStatus, installGamificationAssetStyle } from "./services/gamification-assets.js";
|
|
43
45
|
import { getInsightsPayload } from "./services/insights.js";
|
|
44
46
|
import { buildLifeForcePayload, createFatigueSignal, listLifeForceTemplates, resolveLifeForceUser, updateLifeForceProfile, updateLifeForceTemplate } from "./services/life-force.js";
|
|
45
47
|
import { createEntities, deleteEntities, deleteEntity, getSettingsBinPayload, restoreEntities, searchEntities, updateEntities } from "./services/entity-crud.js";
|
|
@@ -62,7 +64,7 @@ import { buildOpenApiDocument } from "./openapi.js";
|
|
|
62
64
|
import { registerWebRoutes } from "./web.js";
|
|
63
65
|
import { createManagerRuntime } from "./managers/runtime.js";
|
|
64
66
|
import { isManagerError } from "./managers/type-guards.js";
|
|
65
|
-
import { createCompanionPairingSession, createCompanionPairingSessionSchema, createSleepSession, createSleepSessionSchema, createWorkoutSession, createWorkoutSessionSchema, deleteSleepSession, deleteWorkoutSession, getCompanionPairingSessionById, getCompanionOverview, getFitnessViewData, getSleepSessionById, getSleepSessionDetailById, getSleepTimelineOverlaysForRange, getSleepViewData, getVitalsViewData, getWorkoutSessionById, ingestMobileHealthSync, mobileHealthSyncSchema, patchCompanionPairingSourceState, patchCompanionPairingSourceStateSchema, companionSourceKeySchema, requireValidPairing, revokeAllCompanionPairingSessions, revokeAllCompanionPairingSessionsSchema, revokeCompanionPairingSession, updateMobileCompanionSourceState, updateMobileCompanionSourceStateSchema, verifyCompanionPairing, verifyCompanionPairingSchema, updateSleepMetadata, updateSleepMetadataSchema, updateWorkoutMetadata, updateWorkoutMetadataSchema } from "./health.js";
|
|
67
|
+
import { createCompanionPairingSession, createCompanionPairingSessionSchema, createSleepSession, createSleepSessionSchema, createWorkoutSession, createWorkoutSessionSchema, deleteSleepSession, deleteWorkoutSession, getCompanionPairingSessionById, getCompanionOverview, getFitnessViewData, getSleepSessionById, getSleepSessionDetailById, getSleepTimelineOverlaysForRange, getSleepViewData, getVitalsViewData, getWorkoutSessionById, heartbeatCompanionPairing, heartbeatCompanionPairingSchema, ingestMobileHealthSync, mobileHealthSyncSchema, patchCompanionPairingSourceState, patchCompanionPairingSourceStateSchema, companionSourceKeySchema, requireValidPairing, revokeAllCompanionPairingSessions, revokeAllCompanionPairingSessionsSchema, revokeCompanionPairingSession, updateMobileCompanionSourceState, updateMobileCompanionSourceStateSchema, verifyCompanionPairing, verifyCompanionPairingSchema, updateSleepMetadata, updateSleepMetadataSchema, updateWorkoutMetadata, updateWorkoutMetadataSchema } from "./health.js";
|
|
66
68
|
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";
|
|
67
69
|
import { getScreenTimeAllTimeSummary, getScreenTimeDayDetail, getScreenTimeMonthSummary, getScreenTimeSettings, screenTimeSettingsPatchSchema, updateScreenTimeSettings } from "./screen-time.js";
|
|
68
70
|
import { assertWatchReady, buildWatchBootstrap, ingestWatchCaptureBatch, mobileWatchBootstrapSchema, mobileWatchCaptureBatchSchema, mobileWatchHabitCheckInSchema } from "./watch-mobile.js";
|
|
@@ -1955,7 +1957,7 @@ function buildPreferredMutationPath(entityType) {
|
|
|
1955
1957
|
case "wiki_page":
|
|
1956
1958
|
return "Use /api/v1/wiki/pages with POST or PATCH for page CRUD.";
|
|
1957
1959
|
case "calendar_connection":
|
|
1958
|
-
return "Use /api/v1/calendar/
|
|
1960
|
+
return "Use /api/v1/calendar/discovery or /api/v1/calendar/macos-local/discovery before setup when needed; use /api/v1/calendar/connections with POST, PATCH, DELETE, rediscovery, and sync for connection lifecycle work.";
|
|
1959
1961
|
case "task_run":
|
|
1960
1962
|
return "Use the task-run action routes to start, heartbeat, focus, complete, or release live work.";
|
|
1961
1963
|
case "questionnaire_run":
|
|
@@ -1990,7 +1992,7 @@ function buildPreferredMutationTool(entityType) {
|
|
|
1990
1992
|
case "wiki_page":
|
|
1991
1993
|
return "forge_upsert_wiki_page";
|
|
1992
1994
|
case "calendar_connection":
|
|
1993
|
-
return "forge_connect_calendar_provider | forge_sync_calendar_connection";
|
|
1995
|
+
return "forge_connect_calendar_provider | forge_sync_calendar_connection | mirrored calendar connection routes";
|
|
1994
1996
|
case "task_run":
|
|
1995
1997
|
return "forge_start_task_run | forge_heartbeat_task_run | forge_focus_task_run | forge_complete_task_run | forge_release_task_run";
|
|
1996
1998
|
case "questionnaire_run":
|
|
@@ -3200,9 +3202,10 @@ const AGENT_ONBOARDING_PSYCHE_PLAYBOOKS = [
|
|
|
3200
3202
|
useWhen: "Use for a lived direction, quality of being, or way of showing up that matters to the user and should guide actions rather than just describe an outcome.",
|
|
3201
3203
|
coachingGoal: "Clarify the value as a chosen direction, distinguish it from a goal, and gather one concrete way the user wants to embody it now.",
|
|
3202
3204
|
askSequence: [
|
|
3203
|
-
"Start with
|
|
3204
|
-
"Ask
|
|
3205
|
-
"
|
|
3205
|
+
"Start with one ordinary recent moment where the value felt alive, absent, or painfully important.",
|
|
3206
|
+
"Ask what mattered in that moment and why it matters now.",
|
|
3207
|
+
"Reflect the direction in the user's own language before separating it from any specific outcome or achievement goal.",
|
|
3208
|
+
"Ask what someone would see this week if the user lived this value a little more.",
|
|
3206
3209
|
"Notice tensions, barriers, or situations where the value gets lost.",
|
|
3207
3210
|
"Name one small committed action that would move toward the value."
|
|
3208
3211
|
],
|
|
@@ -3217,6 +3220,7 @@ const AGENT_ONBOARDING_PSYCHE_PLAYBOOKS = [
|
|
|
3217
3220
|
"linkedTaskIds"
|
|
3218
3221
|
],
|
|
3219
3222
|
exampleQuestions: [
|
|
3223
|
+
"Where did this value show up recently, even faintly?",
|
|
3220
3224
|
"What feels deeply important about this to you?",
|
|
3221
3225
|
"If you were living this value a little more this week, what would someone be able to see?",
|
|
3222
3226
|
"What goal or area of life does this value belong to most clearly?",
|
|
@@ -3321,12 +3325,12 @@ const AGENT_ONBOARDING_PSYCHE_PLAYBOOKS = [
|
|
|
3321
3325
|
useWhen: "Use for a belief, rule, or self-statement that keeps showing up in reactions, especially when the user can phrase it as a sentence.",
|
|
3322
3326
|
coachingGoal: "Turn implicit self-talk or a likely schema theme into one explicit belief statement that can be tested and linked to patterns, reports, and modes without forcing the user into a debate too early.",
|
|
3323
3327
|
askSequence: [
|
|
3324
|
-
"
|
|
3325
|
-
"
|
|
3326
|
-
"
|
|
3327
|
-
"
|
|
3328
|
-
"
|
|
3329
|
-
"
|
|
3328
|
+
"Anchor the belief in one recent moment or reaction before abstracting it.",
|
|
3329
|
+
"Reflect the likely belief sentence in the user's own words and ask for confirmation or correction.",
|
|
3330
|
+
"Condense it into one saveable statement only after the wording feels accurate.",
|
|
3331
|
+
"Decide whether it is absolute or conditional after the sentence lands.",
|
|
3332
|
+
"Estimate how true it feels from 0 to 100 only if that helps the user understand its grip or guide later review.",
|
|
3333
|
+
"Explore evidence, origin, and a flexible alternative only if the user wants to examine or soften the belief now.",
|
|
3330
3334
|
"Link a schemaId only when a real schema catalog match is known."
|
|
3331
3335
|
],
|
|
3332
3336
|
requiredForCreate: ["statement", "beliefType"],
|
|
@@ -3342,6 +3346,7 @@ const AGENT_ONBOARDING_PSYCHE_PLAYBOOKS = [
|
|
|
3342
3346
|
"linkedModeIds"
|
|
3343
3347
|
],
|
|
3344
3348
|
exampleQuestions: [
|
|
3349
|
+
"When did this belief show up most recently?",
|
|
3345
3350
|
"If we turned that reaction into one sentence, what would it sound like?",
|
|
3346
3351
|
"When that reaction hits, what does it start telling you?",
|
|
3347
3352
|
"Is it more of an always/never belief, or an if-then rule?",
|
|
@@ -3354,6 +3359,7 @@ const AGENT_ONBOARDING_PSYCHE_PLAYBOOKS = [
|
|
|
3354
3359
|
"Schema catalog entries are reference concepts; belief_entry is the user-owned record.",
|
|
3355
3360
|
"If no schema catalog match is known, omit schemaId rather than inventing one.",
|
|
3356
3361
|
"Do not argue the user out of the belief. Reflect it, understand its function, and then collaboratively test for flexibility.",
|
|
3362
|
+
"Do not rush to confidence, evidence, or flexible alternatives before the user feels the belief has been captured.",
|
|
3357
3363
|
"When the wording is nearly there, ask whether it feels true enough before you move into confidence, evidence, or alternative-belief details.",
|
|
3358
3364
|
"A useful hypothesis should name the rule or prediction the moment seems to activate and then invite correction before saving it as the belief sentence."
|
|
3359
3365
|
]
|
|
@@ -3399,6 +3405,7 @@ const AGENT_ONBOARDING_PSYCHE_PLAYBOOKS = [
|
|
|
3399
3405
|
"Mode profiles are durable parts descriptions.",
|
|
3400
3406
|
"Mode guide sessions are the guided reasoning process that can lead toward a mode profile.",
|
|
3401
3407
|
"Do not overpathologize. The point is to understand the part's job and cost, then increase choice.",
|
|
3408
|
+
"Do not start by asking for the mode family; choose the family after the lived description, protective job, fear, or burden is visible enough.",
|
|
3402
3409
|
"If the user asks to understand the mode first, start from a recent moment and ask what the part is trying to do before you name it.",
|
|
3403
3410
|
"When enough evidence is present, offer one tentative hypothesis about the mode's protective job, fear, or burden before choosing the family label."
|
|
3404
3411
|
]
|
|
@@ -3435,12 +3442,13 @@ const AGENT_ONBOARDING_PSYCHE_PLAYBOOKS = [
|
|
|
3435
3442
|
useWhen: "Use for one specific emotionally meaningful incident that should be mapped from situation through emotions, thoughts, behaviors, consequences, and next moves.",
|
|
3436
3443
|
coachingGoal: "Help the user build a clear incident chain with enough structure to learn from one episode while staying grounded and not rushing past the user's felt experience.",
|
|
3437
3444
|
askSequence: [
|
|
3438
|
-
"
|
|
3439
|
-
"
|
|
3440
|
-
"Capture emotions and intensity.",
|
|
3445
|
+
"Start with the situation and felt stake: what happened, and why did it hit enough to save.",
|
|
3446
|
+
"Name the incident briefly only after the concrete sequence is clear.",
|
|
3447
|
+
"Capture emotions, body state, and intensity before moving into interpretation.",
|
|
3441
3448
|
"Capture thoughts, meanings, or belief-linked interpretations.",
|
|
3442
|
-
"Capture behaviors and immediate coping moves.",
|
|
3443
|
-
"Capture short
|
|
3449
|
+
"Capture behaviors, urges, and immediate coping moves.",
|
|
3450
|
+
"Capture what the move did short term and what it cost or changed later.",
|
|
3451
|
+
"Offer one careful hypothesis about the sequence only after situation, emotion, meaning, behavior, and consequence are partly visible.",
|
|
3444
3452
|
"Identify next moves and linked patterns, beliefs, modes, values, or tasks."
|
|
3445
3453
|
],
|
|
3446
3454
|
requiredForCreate: ["title"],
|
|
@@ -3472,6 +3480,7 @@ const AGENT_ONBOARDING_PSYCHE_PLAYBOOKS = [
|
|
|
3472
3480
|
notes: [
|
|
3473
3481
|
"Use eventTypeId only when a known event taxonomy item fits; otherwise use customEventType.",
|
|
3474
3482
|
"Use emotionDefinitionId only when a known emotion definition fits; otherwise keep the raw label.",
|
|
3483
|
+
"Do not turn the report into a worksheet dump before the felt stake is clear; reflect what made the episode matter before asking for the full chain.",
|
|
3475
3484
|
"If the user becomes overwhelmed, slow down, summarize, and return to one segment of the chain at a time instead of pushing for the full report in one turn.",
|
|
3476
3485
|
"Only hypothesize about the incident sequence after the situation, emotion, meaning, behavior, and consequence are at least partly visible."
|
|
3477
3486
|
]
|
|
@@ -4229,8 +4238,12 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4229
4238
|
},
|
|
4230
4239
|
calendar_connection: {
|
|
4231
4240
|
list: "/api/v1/calendar/connections",
|
|
4241
|
+
discover: "/api/v1/calendar/discovery",
|
|
4242
|
+
discoverMacOSLocal: "/api/v1/calendar/macos-local/discovery",
|
|
4243
|
+
rediscover: "/api/v1/calendar/connections/:id/discovery",
|
|
4232
4244
|
create: "/api/v1/calendar/connections",
|
|
4233
4245
|
update: "/api/v1/calendar/connections/:id",
|
|
4246
|
+
sync: "/api/v1/calendar/connections/:id/sync",
|
|
4234
4247
|
delete: "/api/v1/calendar/connections/:id"
|
|
4235
4248
|
}
|
|
4236
4249
|
},
|
|
@@ -4304,6 +4317,7 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4304
4317
|
specializedDomainSurfaces: {
|
|
4305
4318
|
movement: {
|
|
4306
4319
|
classification: "specialized_domain_surface",
|
|
4320
|
+
aliases: ["movement", "Movement"],
|
|
4307
4321
|
summary: "Dedicated movement workspace API. Use these routes for stays, trips, time-in-place questions, visited places, trip detail, selection aggregates, user-defined overlays, and repair actions on already-recorded movement data.",
|
|
4308
4322
|
routeSelectionQuestions: [
|
|
4309
4323
|
"Is the user asking for a day, month, all-time, timeline, place, trip detail, or selected-span answer?",
|
|
@@ -4347,6 +4361,7 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4347
4361
|
},
|
|
4348
4362
|
lifeForce: {
|
|
4349
4363
|
classification: "specialized_domain_surface",
|
|
4364
|
+
aliases: ["life_force", "life-force", "Life Force"],
|
|
4350
4365
|
summary: "Dedicated life-force API. Use it to read the current energy budget, drains, recommendations, and warnings, then patch only the parts that are meant to be user-controlled.",
|
|
4351
4366
|
routeSelectionQuestions: [
|
|
4352
4367
|
"Is the user trying to understand the overview, change durable profile assumptions, change a weekday curve, or log a right-now fatigue signal?",
|
|
@@ -4370,11 +4385,39 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4370
4385
|
"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."
|
|
4371
4386
|
]
|
|
4372
4387
|
},
|
|
4388
|
+
life_force: {
|
|
4389
|
+
classification: "specialized_domain_surface",
|
|
4390
|
+
aliases: ["lifeForce", "life-force", "Life Force"],
|
|
4391
|
+
summary: "Alias for the dedicated Life Force API keyed to the entity-style name `life_force`. Use the same overview, profile, weekday-template, and fatigue-signal routes as `lifeForce`.",
|
|
4392
|
+
routeSelectionQuestions: [
|
|
4393
|
+
"Is the user trying to understand the overview, change durable profile assumptions, change a weekday curve, or log a right-now fatigue signal?",
|
|
4394
|
+
"Are they describing a repeatable weekly shape or a one-off current state?",
|
|
4395
|
+
"If the lane is already clear, what one weekday, profile field, or signal detail is still missing?"
|
|
4396
|
+
],
|
|
4397
|
+
readRoutes: {
|
|
4398
|
+
overview: "/api/v1/life-force"
|
|
4399
|
+
},
|
|
4400
|
+
writeRoutes: {
|
|
4401
|
+
profile: "/api/v1/life-force/profile",
|
|
4402
|
+
weekdayTemplate: "/api/v1/life-force/templates/:weekday",
|
|
4403
|
+
fatigueSignal: "/api/v1/life-force/fatigue-signals"
|
|
4404
|
+
},
|
|
4405
|
+
notes: [
|
|
4406
|
+
"This `life_force` key exists so agents can look up the specialized route family by the entity catalog name without guessing that the canonical surface key is `lifeForce`.",
|
|
4407
|
+
"Life Force is a focused domain surface, not a batch CRUD entity type.",
|
|
4408
|
+
"Use GET /api/v1/life-force for the current overview payload with stats, drains, recommendations, and current-curve state.",
|
|
4409
|
+
"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.",
|
|
4410
|
+
"If the user says something like 'I always dip on Tuesdays after lunch', treat that as a weekday-template change rather than a one-off fatigue signal.",
|
|
4411
|
+
"If the user is asking what changed after a profile, template, or fatigue write, read the overview back so the effect stays visible.",
|
|
4412
|
+
"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."
|
|
4413
|
+
]
|
|
4414
|
+
},
|
|
4373
4415
|
workbench: {
|
|
4374
4416
|
classification: "specialized_domain_surface",
|
|
4417
|
+
aliases: ["workbench", "Workbench"],
|
|
4375
4418
|
summary: "Dedicated graph-flow API. Use it for flow catalog reads, flow CRUD, execution, run history, published outputs, node results, and latest successful node outputs.",
|
|
4376
4419
|
routeSelectionQuestions: [
|
|
4377
|
-
"Is the job flow discovery, flow editing, execution, published output, run detail, node result, latest node output, or flow chat follow-up?",
|
|
4420
|
+
"Is the job flow discovery, flow editing, execution, run history, published output, run detail, node result, latest node output, or flow chat follow-up?",
|
|
4378
4421
|
"Does the user need a stable public contract or one execution artifact?",
|
|
4379
4422
|
"If the flow is already known, what one run, node, or output scope detail is still missing before acting?"
|
|
4380
4423
|
],
|
|
@@ -6376,6 +6419,7 @@ export async function buildServer(options = {}) {
|
|
|
6376
6419
|
storageRoot: getEffectiveDataRoot(),
|
|
6377
6420
|
dataDir: resolveDataDir(),
|
|
6378
6421
|
databasePath: resolveDatabasePathForDataRoot(),
|
|
6422
|
+
port: runtimeConfig.port,
|
|
6379
6423
|
basePath: runtimeConfig.basePath,
|
|
6380
6424
|
devWebOrigin: process.env.FORGE_DEV_WEB_ORIGIN?.trim() || null
|
|
6381
6425
|
};
|
|
@@ -6384,34 +6428,72 @@ export async function buildServer(options = {}) {
|
|
|
6384
6428
|
backend: "forge-node-runtime",
|
|
6385
6429
|
runtime
|
|
6386
6430
|
});
|
|
6387
|
-
const warnings = [];
|
|
6388
|
-
if (!settingsFile.valid) {
|
|
6389
|
-
warnings.push(`forge.json is invalid at ${settingsFile.path}. Forge ignored file precedence until the JSON is repaired or rewritten.`);
|
|
6390
|
-
}
|
|
6391
|
-
if (settingsFile.syncState === "applied_file_overrides") {
|
|
6392
|
-
warnings.push("forge.json overrode one or more persisted database settings on this run.");
|
|
6393
|
-
}
|
|
6394
|
-
if (health.ok === false) {
|
|
6395
|
-
warnings.push("The task-run watchdog reported degraded health.");
|
|
6396
|
-
}
|
|
6397
6431
|
return {
|
|
6398
|
-
doctor: {
|
|
6399
|
-
|
|
6400
|
-
|
|
6432
|
+
doctor: await buildForgeDoctorReport({
|
|
6433
|
+
settings,
|
|
6434
|
+
settingsFile,
|
|
6401
6435
|
runtime,
|
|
6402
|
-
health
|
|
6436
|
+
health
|
|
6437
|
+
})
|
|
6438
|
+
};
|
|
6439
|
+
});
|
|
6440
|
+
app.post("/api/v1/doctor/fixes", async (request) => {
|
|
6441
|
+
requireScopedAccess(request.headers, ["write"], { route: "/api/v1/doctor/fixes" });
|
|
6442
|
+
const parsed = z
|
|
6443
|
+
.object({
|
|
6444
|
+
fixIds: z.array(z.string().min(1)).optional(),
|
|
6445
|
+
applyAllSafe: z.boolean().optional()
|
|
6446
|
+
})
|
|
6447
|
+
.parse(request.body ?? {});
|
|
6448
|
+
const initialSettings = getSettings();
|
|
6449
|
+
const initialSettingsFile = getSettingsFileStatus();
|
|
6450
|
+
const initialRuntime = {
|
|
6451
|
+
pid: process.pid,
|
|
6452
|
+
storageRoot: getEffectiveDataRoot(),
|
|
6453
|
+
dataDir: resolveDataDir(),
|
|
6454
|
+
databasePath: resolveDatabasePathForDataRoot(),
|
|
6455
|
+
port: runtimeConfig.port,
|
|
6456
|
+
basePath: runtimeConfig.basePath,
|
|
6457
|
+
devWebOrigin: process.env.FORGE_DEV_WEB_ORIGIN?.trim() || null
|
|
6458
|
+
};
|
|
6459
|
+
const initialHealth = buildHealthPayload(taskRunWatchdog, {
|
|
6460
|
+
apiVersion: "v1",
|
|
6461
|
+
backend: "forge-node-runtime",
|
|
6462
|
+
runtime: initialRuntime
|
|
6463
|
+
});
|
|
6464
|
+
const initialDoctor = await buildForgeDoctorReport({
|
|
6465
|
+
settings: initialSettings,
|
|
6466
|
+
settingsFile: initialSettingsFile,
|
|
6467
|
+
runtime: initialRuntime,
|
|
6468
|
+
health: initialHealth
|
|
6469
|
+
});
|
|
6470
|
+
const fixResult = applyForgeDoctorFixes(parsed, {
|
|
6471
|
+
integrityScore: initialDoctor.integrity.score
|
|
6472
|
+
});
|
|
6473
|
+
const settings = getSettings();
|
|
6474
|
+
const settingsFile = getSettingsFileStatus();
|
|
6475
|
+
const runtime = {
|
|
6476
|
+
pid: process.pid,
|
|
6477
|
+
storageRoot: getEffectiveDataRoot(),
|
|
6478
|
+
dataDir: resolveDataDir(),
|
|
6479
|
+
databasePath: resolveDatabasePathForDataRoot(),
|
|
6480
|
+
port: runtimeConfig.port,
|
|
6481
|
+
basePath: runtimeConfig.basePath,
|
|
6482
|
+
devWebOrigin: process.env.FORGE_DEV_WEB_ORIGIN?.trim() || null
|
|
6483
|
+
};
|
|
6484
|
+
const health = buildHealthPayload(taskRunWatchdog, {
|
|
6485
|
+
apiVersion: "v1",
|
|
6486
|
+
backend: "forge-node-runtime",
|
|
6487
|
+
runtime
|
|
6488
|
+
});
|
|
6489
|
+
return {
|
|
6490
|
+
...fixResult,
|
|
6491
|
+
doctor: await buildForgeDoctorReport({
|
|
6492
|
+
settings,
|
|
6403
6493
|
settingsFile,
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
|
|
6407
|
-
operatorName: settings.profile.operatorName,
|
|
6408
|
-
maxActiveTasks: settings.execution.maxActiveTasks,
|
|
6409
|
-
timeAccountingMode: settings.execution.timeAccountingMode,
|
|
6410
|
-
psycheAuthRequired: settings.security.psycheAuthRequired,
|
|
6411
|
-
webAppUrl: `http://127.0.0.1:${runtimeConfig.port}${runtimeConfig.basePath}`
|
|
6412
|
-
},
|
|
6413
|
-
warnings
|
|
6414
|
-
}
|
|
6494
|
+
runtime,
|
|
6495
|
+
health
|
|
6496
|
+
})
|
|
6415
6497
|
};
|
|
6416
6498
|
});
|
|
6417
6499
|
app.get("/api/v1/auth/operator-session", async (request, reply) => ({
|
|
@@ -6852,6 +6934,7 @@ export async function buildServer(options = {}) {
|
|
|
6852
6934
|
app.post("/api/v1/mobile/pairing/verify", async (request) => ({
|
|
6853
6935
|
pairing: verifyCompanionPairing(verifyCompanionPairingSchema.parse(request.body ?? {}))
|
|
6854
6936
|
}));
|
|
6937
|
+
app.post("/api/v1/mobile/pairing/heartbeat", async (request) => heartbeatCompanionPairing(heartbeatCompanionPairingSchema.parse(request.body ?? {})));
|
|
6855
6938
|
app.post("/api/v1/mobile/movement/bootstrap", async (request) => {
|
|
6856
6939
|
const parsed = movementMobileBootstrapSchema.parse(request.body ?? {});
|
|
6857
6940
|
const pairing = requireValidPairing(parsed.sessionId, parsed.pairingToken);
|
|
@@ -9137,6 +9220,32 @@ export async function buildServer(options = {}) {
|
|
|
9137
9220
|
catalog: buildGamificationCatalogPayload(filterOwnedEntities("goal", listGoals(), userIds), filterOwnedEntities("task", listTasks({ userIds }), userIds), filterOwnedEntities("habit", listHabits(), userIds), { userIds })
|
|
9138
9221
|
};
|
|
9139
9222
|
});
|
|
9223
|
+
app.get("/api/v1/gamification/assets", async () => ({
|
|
9224
|
+
assets: await getGamificationAssetStatus()
|
|
9225
|
+
}));
|
|
9226
|
+
app.post("/api/v1/gamification/assets/install", async (request, reply) => {
|
|
9227
|
+
requireOperatorSession(request.headers, {
|
|
9228
|
+
route: "/api/v1/gamification/assets/install"
|
|
9229
|
+
});
|
|
9230
|
+
const input = z
|
|
9231
|
+
.object({
|
|
9232
|
+
style: z.enum(["dark-fantasy", "dramatic-smithie", "mind-locksmith"])
|
|
9233
|
+
})
|
|
9234
|
+
.parse(request.body ?? {});
|
|
9235
|
+
try {
|
|
9236
|
+
return {
|
|
9237
|
+
style: await installGamificationAssetStyle(input.style)
|
|
9238
|
+
};
|
|
9239
|
+
}
|
|
9240
|
+
catch (error) {
|
|
9241
|
+
reply.code(502);
|
|
9242
|
+
return {
|
|
9243
|
+
error: error instanceof Error
|
|
9244
|
+
? error.message
|
|
9245
|
+
: "Could not install gamification assets."
|
|
9246
|
+
};
|
|
9247
|
+
}
|
|
9248
|
+
});
|
|
9140
9249
|
app.get("/api/v1/gamification/equipment", async (request) => {
|
|
9141
9250
|
const userIds = resolveScopedUserIds(request.query);
|
|
9142
9251
|
const catalog = buildGamificationCatalogPayload(filterOwnedEntities("goal", listGoals(), userIds), filterOwnedEntities("task", listTasks({ userIds }), userIds), filterOwnedEntities("habit", listHabits(), userIds), { userIds });
|
|
@@ -75,6 +75,7 @@ export const dataManagementSettingsSchema = z.object({
|
|
|
75
75
|
preferredDataRoot: z.string(),
|
|
76
76
|
backupDirectory: z.string(),
|
|
77
77
|
backupFrequencyHours: z.number().int().positive().nullable(),
|
|
78
|
+
backupRetentionDays: z.number().int().positive().nullable(),
|
|
78
79
|
autoRepairEnabled: z.boolean(),
|
|
79
80
|
lastAutoBackupAt: z.string().nullable(),
|
|
80
81
|
lastManualBackupAt: z.string().nullable()
|
|
@@ -89,6 +90,7 @@ export const dataManagementStateSchema = z.object({
|
|
|
89
90
|
export const updateDataManagementSettingsSchema = z.object({
|
|
90
91
|
backupDirectory: z.string().trim().optional(),
|
|
91
92
|
backupFrequencyHours: z.number().int().positive().nullable().optional(),
|
|
93
|
+
backupRetentionDays: z.number().int().positive().nullable().optional(),
|
|
92
94
|
autoRepairEnabled: z.boolean().optional()
|
|
93
95
|
});
|
|
94
96
|
export const createDataBackupSchema = z.object({
|
|
@@ -260,6 +260,16 @@ export const verifyCompanionPairingSchema = z.object({
|
|
|
260
260
|
sourceDevice: z.string().trim().default("iPhone")
|
|
261
261
|
})
|
|
262
262
|
});
|
|
263
|
+
export const heartbeatCompanionPairingSchema = z.object({
|
|
264
|
+
sessionId: z.string().trim().min(1),
|
|
265
|
+
pairingToken: z.string().trim().min(1),
|
|
266
|
+
device: z.object({
|
|
267
|
+
name: z.string().trim().default("iPhone"),
|
|
268
|
+
platform: z.string().trim().default("ios"),
|
|
269
|
+
appVersion: z.string().trim().default(""),
|
|
270
|
+
sourceDevice: z.string().trim().default("iPhone")
|
|
271
|
+
})
|
|
272
|
+
});
|
|
263
273
|
export const updateWorkoutMetadataSchema = z.object({
|
|
264
274
|
subjectiveEffort: z.number().int().min(1).max(10).nullable().optional(),
|
|
265
275
|
moodBefore: z.string().trim().optional(),
|
|
@@ -1555,6 +1565,36 @@ export function verifyCompanionPairing(payload) {
|
|
|
1555
1565
|
.get(pairing.id))
|
|
1556
1566
|
};
|
|
1557
1567
|
}
|
|
1568
|
+
export function heartbeatCompanionPairing(payload) {
|
|
1569
|
+
const parsed = heartbeatCompanionPairingSchema.parse(payload);
|
|
1570
|
+
const pairing = requireValidPairing(parsed.sessionId, parsed.pairingToken);
|
|
1571
|
+
const now = nowIso();
|
|
1572
|
+
const renewedExpiry = nextVerifiedCompanionPairingExpiry(new Date());
|
|
1573
|
+
const nextStatus = pairing.status === "revoked"
|
|
1574
|
+
? pairing.status
|
|
1575
|
+
: pairing.status === "permission_denied"
|
|
1576
|
+
? pairing.status
|
|
1577
|
+
: pairing.status === "stale"
|
|
1578
|
+
? "paired"
|
|
1579
|
+
: pairing.status === "pending"
|
|
1580
|
+
? "paired"
|
|
1581
|
+
: pairing.status;
|
|
1582
|
+
getDatabase()
|
|
1583
|
+
.prepare(`UPDATE companion_pairing_sessions
|
|
1584
|
+
SET status = ?, device_name = ?, platform = ?, app_version = ?,
|
|
1585
|
+
last_seen_at = ?, paired_at = COALESCE(paired_at, ?),
|
|
1586
|
+
expires_at = ?, updated_at = ?
|
|
1587
|
+
WHERE id = ?`)
|
|
1588
|
+
.run(nextStatus, parsed.device.name, parsed.device.platform, parsed.device.appVersion, now, now, renewedExpiry, now, pairing.id);
|
|
1589
|
+
ensurePairingSourceStates(getDatabase()
|
|
1590
|
+
.prepare(`SELECT * FROM companion_pairing_sessions WHERE id = ?`)
|
|
1591
|
+
.get(pairing.id));
|
|
1592
|
+
return {
|
|
1593
|
+
pairingSession: mapPairingSession(getDatabase()
|
|
1594
|
+
.prepare(`SELECT * FROM companion_pairing_sessions WHERE id = ?`)
|
|
1595
|
+
.get(pairing.id))
|
|
1596
|
+
};
|
|
1597
|
+
}
|
|
1558
1598
|
export function requireValidPairing(sessionId, pairingToken) {
|
|
1559
1599
|
const row = getDatabase()
|
|
1560
1600
|
.prepare(`SELECT * FROM companion_pairing_sessions WHERE id = ?`)
|