forge-openclaw-plugin 0.2.7 → 0.2.10
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 +73 -1
- package/dist/assets/{board-CzgvdLO8.js → board-C_m78kvK.js} +2 -2
- package/dist/assets/{board-CzgvdLO8.js.map → board-C_m78kvK.js.map} +1 -1
- package/dist/assets/index-BWtLtXwb.js +36 -0
- package/dist/assets/index-BWtLtXwb.js.map +1 -0
- package/dist/assets/index-Dp5GXY_z.css +1 -0
- package/dist/assets/{motion-STUd1O46.js → motion-CpZvZumD.js} +2 -2
- package/dist/assets/{motion-STUd1O46.js.map → motion-CpZvZumD.js.map} +1 -1
- package/dist/assets/{table-CtNlETLc.js → table-DtyXTw03.js} +2 -2
- package/dist/assets/{table-CtNlETLc.js.map → table-DtyXTw03.js.map} +1 -1
- package/dist/assets/{ui-ThzkR_oW.js → ui-BXbpiKyS.js} +2 -2
- package/dist/assets/{ui-ThzkR_oW.js.map → ui-BXbpiKyS.js.map} +1 -1
- package/dist/assets/{vendor-DyHAI6nk.js → vendor-QBH6qVEe.js} +84 -74
- package/dist/assets/vendor-QBH6qVEe.js.map +1 -0
- package/dist/assets/{viz-BJuBCz_G.js → viz-w-IMeueL.js} +2 -2
- package/dist/assets/{viz-BJuBCz_G.js.map → viz-w-IMeueL.js.map} +1 -1
- package/dist/index.html +8 -8
- package/dist/openclaw/api-client.d.ts +1 -0
- package/dist/openclaw/local-runtime.js +2 -1
- package/dist/openclaw/plugin-entry-shared.js +12 -0
- package/dist/server/app.js +104 -67
- package/dist/server/demo-data.js +49 -0
- package/dist/server/openapi.js +84 -43
- package/dist/server/psyche-types.js +1 -30
- package/dist/server/repositories/deleted-entities.js +60 -26
- package/dist/server/repositories/goals.js +2 -5
- package/dist/server/repositories/notes.js +359 -0
- package/dist/server/repositories/projects.js +2 -5
- package/dist/server/repositories/psyche.js +11 -14
- package/dist/server/repositories/task-runs.js +2 -0
- package/dist/server/repositories/tasks.js +21 -10
- package/dist/server/seed-demo.js +11 -0
- package/dist/server/services/dashboard.js +4 -1
- package/dist/server/services/entity-crud.js +27 -30
- package/dist/server/services/insights.js +5 -5
- package/dist/server/services/projects.js +3 -1
- package/dist/server/services/psyche.js +4 -4
- package/dist/server/types.js +70 -11
- package/openclaw.plugin.json +12 -1
- package/package.json +1 -1
- package/server/migrations/001_core.sql +78 -0
- package/server/migrations/002_psyche.sql +164 -13
- package/skills/forge-openclaw/SKILL.md +17 -5
- package/dist/assets/index-8d_oM8fL.js +0 -27
- package/dist/assets/index-8d_oM8fL.js.map +0 -1
- package/dist/assets/index-D4A_bq8m.css +0 -1
- package/dist/assets/vendor-DyHAI6nk.js.map +0 -1
- package/dist/server/repositories/comments.js +0 -176
- package/server/migrations/003_timer_execution.sql +0 -18
- package/server/migrations/004_psyche_linked_entities.sql +0 -5
- package/server/migrations/005_adaptive_schemas.sql +0 -157
- package/server/migrations/006_psyche_auth_setting.sql +0 -4
- package/server/migrations/007_deleted_entities.sql +0 -16
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { getDatabase, runInTransaction } from "../db.js";
|
|
2
|
-
import { deleteComment, getCommentById, listComments, updateComment, createComment } from "../repositories/comments.js";
|
|
3
2
|
import { createInsight, deleteInsight, getInsightById, listInsights, updateInsight } from "../repositories/collaboration.js";
|
|
4
|
-
import {
|
|
3
|
+
import { createNote, deleteNote, getNoteById, listNotes, unlinkNotesForEntity, updateNote } from "../repositories/notes.js";
|
|
4
|
+
import { createBehaviorPatternSchema, createBehaviorSchema, createBeliefEntrySchema, createEmotionDefinitionSchema, createEventTypeSchema, createModeGuideSessionSchema, createModeProfileSchema, createPsycheValueSchema, createTriggerReportSchema, updateBehaviorPatternSchema, updateBehaviorSchema, updateBeliefEntrySchema, updateEmotionDefinitionSchema, updateEventTypeSchema, updateModeGuideSessionSchema, updateModeProfileSchema, updatePsycheValueSchema, updateTriggerReportSchema } from "../psyche-types.js";
|
|
5
5
|
import { buildSettingsBinPayload, cascadeSoftDeleteAnchoredCollaboration, clearDeletedEntityRecord, getDeletedEntityRecord, listDeletedEntities, restoreAnchoredCollaboration, restoreDeletedEntityRecord, upsertDeletedEntityRecord } from "../repositories/deleted-entities.js";
|
|
6
6
|
import { createGoal, deleteGoal, getGoalById, listGoals, updateGoal } from "../repositories/goals.js";
|
|
7
7
|
import { createBehavior, createBehaviorPattern, createBeliefEntry, createEmotionDefinition, createEventType, createModeGuideSession, createModeProfile, createPsycheValue, createTriggerReport, deleteBehavior, deleteBehaviorPattern, deleteBeliefEntry, deleteEmotionDefinition, deleteEventType, deleteModeGuideSession, deleteModeProfile, deletePsycheValue, deleteTriggerReport, getBehaviorById, getBehaviorPatternById, getBeliefEntryById, getEmotionDefinitionById, getEventTypeById, getModeGuideSessionById, getModeProfileById, getPsycheValueById, getTriggerReportById, listBehaviors, listBehaviorPatterns, listBeliefEntries, listEmotionDefinitions, listEventTypes, listModeGuideSessions, listModeProfiles, listPsycheValues, listTriggerReports, updateBehavior, updateBehaviorPattern, updateBeliefEntry, updateEmotionDefinition, updateEventType, updateModeGuideSession, updateModeProfile, updatePsycheValue, updateTriggerReport } from "../repositories/psyche.js";
|
|
8
8
|
import { createProject, deleteProject, getProjectById, listProjects, updateProject } from "../repositories/projects.js";
|
|
9
9
|
import { createTag, deleteTag, getTagById, listTags, updateTag } from "../repositories/tags.js";
|
|
10
10
|
import { createTask, deleteTask, getTaskById, listTasks, updateTask } from "../repositories/tasks.js";
|
|
11
|
-
import { createGoalSchema, createInsightSchema, createProjectSchema, createTagSchema, createTaskSchema, updateGoalSchema, updateInsightSchema, updateProjectSchema, updateTagSchema, updateTaskSchema } from "../types.js";
|
|
11
|
+
import { createGoalSchema, createInsightSchema, createNoteSchema, createProjectSchema, createTagSchema, createTaskSchema, updateGoalSchema, updateInsightSchema, updateNoteSchema, updateProjectSchema, updateTagSchema, updateTaskSchema } from "../types.js";
|
|
12
12
|
class AtomicBatchRollback extends Error {
|
|
13
13
|
index;
|
|
14
14
|
code;
|
|
@@ -58,14 +58,14 @@ const CRUD_ENTITY_CAPABILITIES = {
|
|
|
58
58
|
update: (id, patch, context) => updateTag(id, patch, context),
|
|
59
59
|
hardDelete: (id, context) => deleteTag(id, context)
|
|
60
60
|
},
|
|
61
|
-
|
|
62
|
-
entityType: "
|
|
63
|
-
routeBase: "/api/v1/
|
|
64
|
-
list: () =>
|
|
65
|
-
get: (id) =>
|
|
66
|
-
create: (data, context) =>
|
|
67
|
-
update: (id, patch, context) =>
|
|
68
|
-
hardDelete: (id, context) =>
|
|
61
|
+
note: {
|
|
62
|
+
entityType: "note",
|
|
63
|
+
routeBase: "/api/v1/notes",
|
|
64
|
+
list: () => listNotes(),
|
|
65
|
+
get: (id) => getNoteById(id),
|
|
66
|
+
create: (data, context) => createNote(data, context),
|
|
67
|
+
update: (id, patch, context) => updateNote(id, patch, context),
|
|
68
|
+
hardDelete: (id, context) => deleteNote(id, context)
|
|
69
69
|
},
|
|
70
70
|
insight: {
|
|
71
71
|
entityType: "insight",
|
|
@@ -175,7 +175,7 @@ const CREATE_ENTITY_SCHEMAS = {
|
|
|
175
175
|
project: createProjectSchema,
|
|
176
176
|
task: createTaskSchema,
|
|
177
177
|
tag: createTagSchema,
|
|
178
|
-
|
|
178
|
+
note: createNoteSchema,
|
|
179
179
|
insight: createInsightSchema,
|
|
180
180
|
psyche_value: createPsycheValueSchema,
|
|
181
181
|
behavior_pattern: createBehaviorPatternSchema,
|
|
@@ -192,7 +192,7 @@ const UPDATE_ENTITY_SCHEMAS = {
|
|
|
192
192
|
project: updateProjectSchema,
|
|
193
193
|
task: updateTaskSchema,
|
|
194
194
|
tag: updateTagSchema,
|
|
195
|
-
|
|
195
|
+
note: updateNoteSchema,
|
|
196
196
|
insight: updateInsightSchema,
|
|
197
197
|
psyche_value: updatePsycheValueSchema,
|
|
198
198
|
behavior_pattern: updateBehaviorPatternSchema,
|
|
@@ -312,7 +312,14 @@ function matchesLinkedTo(entityType, entity, linkedTo) {
|
|
|
312
312
|
return linkedTo.entityType === "goal" && entity.goalId === linkedTo.id;
|
|
313
313
|
case "task":
|
|
314
314
|
return (linkedTo.entityType === "goal" && entity.goalId === linkedTo.id) || (linkedTo.entityType === "project" && entity.projectId === linkedTo.id);
|
|
315
|
-
case "
|
|
315
|
+
case "note":
|
|
316
|
+
return (Array.isArray(entity.links) &&
|
|
317
|
+
entity.links.some((link) => typeof link === "object" &&
|
|
318
|
+
link !== null &&
|
|
319
|
+
"entityType" in link &&
|
|
320
|
+
"entityId" in link &&
|
|
321
|
+
link.entityType === linkedTo.entityType &&
|
|
322
|
+
link.entityId === linkedTo.id));
|
|
316
323
|
case "insight":
|
|
317
324
|
return entity.entityType === linkedTo.entityType && entity.entityId === linkedTo.id;
|
|
318
325
|
case "psyche_value":
|
|
@@ -378,18 +385,7 @@ function purgeAnchoredCollaboration(entityType, entityId) {
|
|
|
378
385
|
.prepare(`DELETE FROM deleted_entities WHERE entity_type = 'insight' AND entity_id IN (${placeholders})`)
|
|
379
386
|
.run(...insightIds.map((row) => row.id));
|
|
380
387
|
}
|
|
381
|
-
|
|
382
|
-
.prepare(`SELECT id FROM entity_comments WHERE entity_type = ? AND entity_id = ?`)
|
|
383
|
-
.all(entityType, entityId);
|
|
384
|
-
if (commentIds.length > 0) {
|
|
385
|
-
const placeholders = commentIds.map(() => "?").join(", ");
|
|
386
|
-
getDatabase()
|
|
387
|
-
.prepare(`DELETE FROM entity_comments WHERE id IN (${placeholders})`)
|
|
388
|
-
.run(...commentIds.map((row) => row.id));
|
|
389
|
-
getDatabase()
|
|
390
|
-
.prepare(`DELETE FROM deleted_entities WHERE entity_type = 'comment' AND entity_id IN (${placeholders})`)
|
|
391
|
-
.run(...commentIds.map((row) => row.id));
|
|
392
|
-
}
|
|
388
|
+
unlinkNotesForEntity(entityType, entityId, { source: "system", actor: null });
|
|
393
389
|
}
|
|
394
390
|
export function deleteEntity(entityType, id, options, context) {
|
|
395
391
|
const capability = getCapability(entityType);
|
|
@@ -417,13 +413,13 @@ export function deleteEntity(entityType, id, options, context) {
|
|
|
417
413
|
deleteReason: options.reason ?? "",
|
|
418
414
|
context
|
|
419
415
|
});
|
|
420
|
-
if (entityType !== "
|
|
416
|
+
if (entityType !== "note" && entityType !== "insight") {
|
|
421
417
|
cascadeSoftDeleteAnchoredCollaboration(entityType, id, context, options.reason ?? "");
|
|
422
418
|
}
|
|
423
419
|
return entity;
|
|
424
420
|
}
|
|
425
421
|
clearDeletedEntityRecord(entityType, id);
|
|
426
|
-
if (entityType !== "
|
|
422
|
+
if (entityType !== "note" && entityType !== "insight") {
|
|
427
423
|
purgeAnchoredCollaboration(entityType, id);
|
|
428
424
|
}
|
|
429
425
|
const deleted = capability.hardDelete(id, context);
|
|
@@ -437,7 +433,7 @@ export function restoreEntity(entityType, id) {
|
|
|
437
433
|
if (!deleted) {
|
|
438
434
|
return undefined;
|
|
439
435
|
}
|
|
440
|
-
if (entityType !== "
|
|
436
|
+
if (entityType !== "note" && entityType !== "insight") {
|
|
441
437
|
restoreAnchoredCollaboration(entityType, id);
|
|
442
438
|
}
|
|
443
439
|
return getCapability(entityType).get(id) ?? deleted.snapshot;
|
|
@@ -539,9 +535,10 @@ export function restoreEntities(input) {
|
|
|
539
535
|
}
|
|
540
536
|
export function searchEntities(input) {
|
|
541
537
|
const deleted = listDeletedEntities();
|
|
538
|
+
const defaultEntityTypes = Object.keys(CRUD_ENTITY_CAPABILITIES);
|
|
542
539
|
return {
|
|
543
540
|
results: input.searches.map((search) => {
|
|
544
|
-
const entityTypes = search.entityTypes && search.entityTypes.length > 0 ? search.entityTypes :
|
|
541
|
+
const entityTypes = search.entityTypes && search.entityTypes.length > 0 ? search.entityTypes : defaultEntityTypes;
|
|
545
542
|
const liveMatches = entityTypes.flatMap((entityType) => getCapability(entityType)
|
|
546
543
|
.list()
|
|
547
544
|
.filter((entity) => (search.ids && search.ids.length > 0 ? search.ids.includes(String(entity.id ?? "")) : true))
|
|
@@ -71,16 +71,16 @@ export function getInsightsPayload(now = new Date()) {
|
|
|
71
71
|
executionTrends: trends,
|
|
72
72
|
domainBalance,
|
|
73
73
|
coaching: {
|
|
74
|
-
title: hottestGoal ? `Protect ${hottestGoal.title}` : "Rebuild momentum",
|
|
74
|
+
title: hottestGoal ? `Protect progress on ${hottestGoal.title}` : "Rebuild momentum",
|
|
75
75
|
summary: blockedTasks > 0
|
|
76
|
-
? `${blockedTasks} blocked task${blockedTasks === 1 ? "" : "s"} are
|
|
76
|
+
? `${blockedTasks} blocked task${blockedTasks === 1 ? "" : "s"} are slowing active work across Forge right now.`
|
|
77
77
|
: overdueTasks > 0
|
|
78
|
-
? `${overdueTasks} overdue task${overdueTasks === 1 ? "" : "s"} are the
|
|
78
|
+
? `${overdueTasks} overdue task${overdueTasks === 1 ? "" : "s"} are creating the biggest execution drag right now.`
|
|
79
79
|
: "Recent evidence shows enough movement to push the next arc more aggressively.",
|
|
80
80
|
recommendation: blockedTasks > 0
|
|
81
|
-
? "Clear one blocked task before adding more new work."
|
|
81
|
+
? "Clear one blocked task before adding more new work so the active lane can move again."
|
|
82
82
|
: hottestGoal
|
|
83
|
-
? `
|
|
83
|
+
? `Create or schedule the next concrete move under ${hottestGoal.title}, then protect one deep-work lane to carry it forward this week.`
|
|
84
84
|
: "Pick one life goal, one project, and one task to stabilize the next 24 hours.",
|
|
85
85
|
ctaLabel: "Trigger coaching insight"
|
|
86
86
|
},
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { listActivityEvents } from "../repositories/activity-events.js";
|
|
2
2
|
import { getGoalById, listGoals } from "../repositories/goals.js";
|
|
3
|
+
import { buildNotesSummaryByEntity } from "../repositories/notes.js";
|
|
3
4
|
import { listProjects } from "../repositories/projects.js";
|
|
4
5
|
import { listTasks } from "../repositories/tasks.js";
|
|
5
6
|
import { emptyTaskTimeSummary } from "./work-time.js";
|
|
@@ -70,6 +71,7 @@ export function getProjectBoard(projectId) {
|
|
|
70
71
|
project,
|
|
71
72
|
goal,
|
|
72
73
|
tasks: listTasks({ projectId }),
|
|
73
|
-
activity: listActivityEvents({ entityType: "project", entityId: projectId, limit: 20 }).concat(listActivityEvents({ entityType: "task", limit: 100 }).filter((event) => listTasks({ projectId }).some((task) => task.id === event.entityId)).slice(0, 20))
|
|
74
|
+
activity: listActivityEvents({ entityType: "project", entityId: projectId, limit: 20 }).concat(listActivityEvents({ entityType: "task", limit: 100 }).filter((event) => listTasks({ projectId }).some((task) => task.id === event.entityId)).slice(0, 20)),
|
|
75
|
+
notesSummaryByEntity: buildNotesSummaryByEntity()
|
|
74
76
|
});
|
|
75
77
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getDomainBySlug } from "../repositories/domains.js";
|
|
2
|
-
import { listComments } from "../repositories/comments.js";
|
|
3
2
|
import { listInsights } from "../repositories/collaboration.js";
|
|
3
|
+
import { listNotes } from "../repositories/notes.js";
|
|
4
4
|
import { listBehaviorPatterns, listBehaviors, listBeliefEntries, listModeProfiles, listPsycheValues, listSchemaCatalog, listTriggerReports } from "../repositories/psyche.js";
|
|
5
5
|
import { psycheOverviewPayloadSchema } from "../psyche-types.js";
|
|
6
6
|
const PSYCHE_ENTITY_TYPE_SET = new Set([
|
|
@@ -23,9 +23,9 @@ export function getPsycheOverview() {
|
|
|
23
23
|
const modes = listModeProfiles();
|
|
24
24
|
const reports = listTriggerReports(5);
|
|
25
25
|
const schemaCatalog = listSchemaCatalog();
|
|
26
|
-
const
|
|
26
|
+
const notes = listNotes({ limit: 200 });
|
|
27
27
|
const openInsights = listInsights({ limit: 100 }).filter((insight) => insight.entityType && PSYCHE_ENTITY_TYPE_SET.has(insight.entityType)).length;
|
|
28
|
-
const
|
|
28
|
+
const openNotes = notes.filter((note) => note.links.some((link) => PSYCHE_ENTITY_TYPE_SET.has(link.entityType))).length;
|
|
29
29
|
const committedActions = [
|
|
30
30
|
...values.flatMap((value) => value.committedActions),
|
|
31
31
|
...behaviors.filter((behavior) => behavior.kind === "committed").map((behavior) => behavior.title),
|
|
@@ -57,7 +57,7 @@ export function getPsycheOverview() {
|
|
|
57
57
|
reports,
|
|
58
58
|
schemaPressure,
|
|
59
59
|
openInsights,
|
|
60
|
-
|
|
60
|
+
openNotes,
|
|
61
61
|
committedActions
|
|
62
62
|
});
|
|
63
63
|
}
|
package/dist/server/types.js
CHANGED
|
@@ -21,8 +21,9 @@ export const activityEntityTypeSchema = z.enum([
|
|
|
21
21
|
"behavior",
|
|
22
22
|
"belief_entry",
|
|
23
23
|
"mode_profile",
|
|
24
|
+
"mode_guide_session",
|
|
24
25
|
"trigger_report",
|
|
25
|
-
"
|
|
26
|
+
"note",
|
|
26
27
|
"event_type",
|
|
27
28
|
"emotion_definition",
|
|
28
29
|
"tag",
|
|
@@ -50,7 +51,7 @@ export const crudEntityTypeSchema = z.enum([
|
|
|
50
51
|
"project",
|
|
51
52
|
"task",
|
|
52
53
|
"tag",
|
|
53
|
-
"
|
|
54
|
+
"note",
|
|
54
55
|
"insight",
|
|
55
56
|
"psyche_value",
|
|
56
57
|
"behavior_pattern",
|
|
@@ -121,6 +122,27 @@ export const taskTimeSummarySchema = z.object({
|
|
|
121
122
|
hasCurrentRun: z.boolean(),
|
|
122
123
|
currentRunId: z.string().nullable()
|
|
123
124
|
});
|
|
125
|
+
export const noteLinkSchema = z.object({
|
|
126
|
+
entityType: crudEntityTypeSchema,
|
|
127
|
+
entityId: nonEmptyTrimmedString,
|
|
128
|
+
anchorKey: trimmedString.nullable().default(null)
|
|
129
|
+
});
|
|
130
|
+
export const noteSchema = z.object({
|
|
131
|
+
id: z.string(),
|
|
132
|
+
contentMarkdown: nonEmptyTrimmedString,
|
|
133
|
+
contentPlain: trimmedString,
|
|
134
|
+
author: z.string().nullable(),
|
|
135
|
+
source: activitySourceSchema,
|
|
136
|
+
createdAt: z.string(),
|
|
137
|
+
updatedAt: z.string(),
|
|
138
|
+
links: z.array(noteLinkSchema).min(1)
|
|
139
|
+
});
|
|
140
|
+
export const noteSummarySchema = z.object({
|
|
141
|
+
count: z.number().int().nonnegative(),
|
|
142
|
+
latestNoteId: z.string().nullable(),
|
|
143
|
+
latestCreatedAt: z.string().nullable()
|
|
144
|
+
});
|
|
145
|
+
export const notesSummaryByEntitySchema = z.record(z.string(), noteSummarySchema);
|
|
124
146
|
export const goalSchema = z.object({
|
|
125
147
|
id: z.string(),
|
|
126
148
|
title: nonEmptyTrimmedString,
|
|
@@ -299,7 +321,8 @@ export const dashboardPayloadSchema = z.object({
|
|
|
299
321
|
gamification: gamificationProfileSchema,
|
|
300
322
|
achievements: z.array(achievementSignalSchema),
|
|
301
323
|
milestoneRewards: z.array(milestoneRewardSchema),
|
|
302
|
-
recentActivity: z.array(activityEventSchema)
|
|
324
|
+
recentActivity: z.array(activityEventSchema),
|
|
325
|
+
notesSummaryByEntity: notesSummaryByEntitySchema.default({})
|
|
303
326
|
});
|
|
304
327
|
export const contextDomainBalanceSchema = z.object({
|
|
305
328
|
tagId: z.string(),
|
|
@@ -379,13 +402,15 @@ export const taskContextPayloadSchema = z.object({
|
|
|
379
402
|
project: projectSummarySchema.nullable(),
|
|
380
403
|
activeTaskRun: taskRunSchema.nullable(),
|
|
381
404
|
taskRuns: z.array(taskRunSchema),
|
|
382
|
-
activity: z.array(activityEventSchema)
|
|
405
|
+
activity: z.array(activityEventSchema),
|
|
406
|
+
notesSummaryByEntity: notesSummaryByEntitySchema.default({})
|
|
383
407
|
});
|
|
384
408
|
export const projectBoardPayloadSchema = z.object({
|
|
385
409
|
project: projectSummarySchema,
|
|
386
410
|
goal: goalSchema,
|
|
387
411
|
tasks: z.array(taskSchema),
|
|
388
|
-
activity: z.array(activityEventSchema)
|
|
412
|
+
activity: z.array(activityEventSchema),
|
|
413
|
+
notesSummaryByEntity: notesSummaryByEntitySchema.default({})
|
|
389
414
|
});
|
|
390
415
|
export const insightsHeatmapCellSchema = z.object({
|
|
391
416
|
id: z.string(),
|
|
@@ -697,6 +722,34 @@ export const settingsBinPayloadSchema = z.object({
|
|
|
697
722
|
countsByEntityType: z.record(z.string(), z.number().int().nonnegative()),
|
|
698
723
|
records: z.array(deletedEntityRecordSchema)
|
|
699
724
|
});
|
|
725
|
+
export const createNoteLinkSchema = z.object({
|
|
726
|
+
entityType: crudEntityTypeSchema,
|
|
727
|
+
entityId: nonEmptyTrimmedString,
|
|
728
|
+
anchorKey: trimmedString.nullable().default(null)
|
|
729
|
+
});
|
|
730
|
+
export const createNoteSchema = z.object({
|
|
731
|
+
contentMarkdown: nonEmptyTrimmedString,
|
|
732
|
+
author: trimmedString.nullable().default(null),
|
|
733
|
+
links: z.array(createNoteLinkSchema).min(1)
|
|
734
|
+
});
|
|
735
|
+
export const nestedCreateNoteSchema = z.object({
|
|
736
|
+
contentMarkdown: nonEmptyTrimmedString,
|
|
737
|
+
author: trimmedString.nullable().default(null),
|
|
738
|
+
links: z.array(createNoteLinkSchema).default([])
|
|
739
|
+
});
|
|
740
|
+
export const updateNoteSchema = z.object({
|
|
741
|
+
contentMarkdown: nonEmptyTrimmedString.optional(),
|
|
742
|
+
author: trimmedString.nullable().optional(),
|
|
743
|
+
links: z.array(createNoteLinkSchema).min(1).optional()
|
|
744
|
+
});
|
|
745
|
+
export const notesListQuerySchema = z.object({
|
|
746
|
+
linkedEntityType: crudEntityTypeSchema.optional(),
|
|
747
|
+
linkedEntityId: nonEmptyTrimmedString.optional(),
|
|
748
|
+
anchorKey: trimmedString.nullable().optional(),
|
|
749
|
+
author: trimmedString.optional(),
|
|
750
|
+
query: trimmedString.optional(),
|
|
751
|
+
limit: z.coerce.number().int().positive().max(200).optional()
|
|
752
|
+
});
|
|
700
753
|
export const taskListQuerySchema = z.object({
|
|
701
754
|
status: taskStatusSchema.optional(),
|
|
702
755
|
owner: nonEmptyTrimmedString.optional(),
|
|
@@ -731,7 +784,8 @@ export const createGoalSchema = z.object({
|
|
|
731
784
|
status: goalStatusSchema.default("active"),
|
|
732
785
|
targetPoints: z.number().int().min(25).max(10000).default(400),
|
|
733
786
|
themeColor: z.string().regex(/^#[0-9a-fA-F]{6}$/).default("#c8a46b"),
|
|
734
|
-
tagIds: uniqueStringArraySchema.default([])
|
|
787
|
+
tagIds: uniqueStringArraySchema.default([]),
|
|
788
|
+
notes: z.array(nestedCreateNoteSchema).default([])
|
|
735
789
|
});
|
|
736
790
|
export const updateGoalSchema = createGoalSchema.partial();
|
|
737
791
|
export const createTagSchema = z.object({
|
|
@@ -747,7 +801,8 @@ export const createProjectSchema = z.object({
|
|
|
747
801
|
description: trimmedString.default(""),
|
|
748
802
|
status: projectStatusSchema.default("active"),
|
|
749
803
|
targetPoints: z.number().int().min(25).max(10000).default(240),
|
|
750
|
-
themeColor: z.string().regex(/^#[0-9a-fA-F]{6}$/).default("#c0c1ff")
|
|
804
|
+
themeColor: z.string().regex(/^#[0-9a-fA-F]{6}$/).default("#c0c1ff"),
|
|
805
|
+
notes: z.array(nestedCreateNoteSchema).default([])
|
|
751
806
|
});
|
|
752
807
|
export const updateProjectSchema = createProjectSchema.partial();
|
|
753
808
|
export const taskMutationShape = {
|
|
@@ -763,7 +818,8 @@ export const taskMutationShape = {
|
|
|
763
818
|
energy: taskEnergySchema.default("steady"),
|
|
764
819
|
points: z.number().int().min(5).max(500).default(40),
|
|
765
820
|
sortOrder: z.number().int().nonnegative().optional(),
|
|
766
|
-
tagIds: uniqueStringArraySchema.default([])
|
|
821
|
+
tagIds: uniqueStringArraySchema.default([]),
|
|
822
|
+
notes: z.array(nestedCreateNoteSchema).default([])
|
|
767
823
|
};
|
|
768
824
|
export const createTaskSchema = z.object(taskMutationShape);
|
|
769
825
|
export const updateTaskSchema = z.object({
|
|
@@ -779,7 +835,8 @@ export const updateTaskSchema = z.object({
|
|
|
779
835
|
energy: taskEnergySchema.optional(),
|
|
780
836
|
points: z.number().int().min(5).max(500).optional(),
|
|
781
837
|
sortOrder: z.number().int().nonnegative().optional(),
|
|
782
|
-
tagIds: uniqueStringArraySchema.optional()
|
|
838
|
+
tagIds: uniqueStringArraySchema.optional(),
|
|
839
|
+
notes: z.array(nestedCreateNoteSchema).optional()
|
|
783
840
|
});
|
|
784
841
|
export const tagSuggestionRequestSchema = z.object({
|
|
785
842
|
title: trimmedString.default(""),
|
|
@@ -817,7 +874,8 @@ export const taskRunHeartbeatSchema = z.object({
|
|
|
817
874
|
});
|
|
818
875
|
export const taskRunFinishSchema = z.object({
|
|
819
876
|
actor: nonEmptyTrimmedString.optional(),
|
|
820
|
-
note: trimmedString.default("")
|
|
877
|
+
note: trimmedString.default(""),
|
|
878
|
+
closeoutNote: nestedCreateNoteSchema.optional()
|
|
821
879
|
});
|
|
822
880
|
export const taskRunFocusSchema = z.object({
|
|
823
881
|
actor: nonEmptyTrimmedString.optional()
|
|
@@ -982,7 +1040,8 @@ export const operatorLogWorkSchema = z
|
|
|
982
1040
|
effort: taskEffortSchema.optional(),
|
|
983
1041
|
energy: taskEnergySchema.optional(),
|
|
984
1042
|
points: z.number().int().min(5).max(500).optional(),
|
|
985
|
-
tagIds: uniqueStringArraySchema.optional()
|
|
1043
|
+
tagIds: uniqueStringArraySchema.optional(),
|
|
1044
|
+
closeoutNote: nestedCreateNoteSchema.optional()
|
|
986
1045
|
})
|
|
987
1046
|
.superRefine((value, context) => {
|
|
988
1047
|
if (!value.taskId && (!value.title || value.title.trim().length === 0)) {
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "forge-openclaw-plugin",
|
|
3
3
|
"name": "Forge",
|
|
4
4
|
"description": "Curated OpenClaw adapter for the Forge collaboration API, UI entrypoint, and localhost auto-start runtime.",
|
|
5
|
-
"version": "0.2.
|
|
5
|
+
"version": "0.2.10",
|
|
6
6
|
"skills": [
|
|
7
7
|
"./skills"
|
|
8
8
|
],
|
|
@@ -17,6 +17,12 @@
|
|
|
17
17
|
"help": "Forge server port. Change this if your local machine uses another port.",
|
|
18
18
|
"placeholder": "4317"
|
|
19
19
|
},
|
|
20
|
+
"dataRoot": {
|
|
21
|
+
"label": "Forge Data Root",
|
|
22
|
+
"help": "Optional absolute folder path for Forge data. Use this when you want Forge to read and write a specific data directory instead of the runtime working directory.",
|
|
23
|
+
"placeholder": "/Users/you/forge-data",
|
|
24
|
+
"advanced": true
|
|
25
|
+
},
|
|
20
26
|
"apiToken": {
|
|
21
27
|
"label": "Forge API Token",
|
|
22
28
|
"help": "Optional bearer token. Leave blank for one-step localhost or Tailscale operator-session bootstrap.",
|
|
@@ -50,6 +56,11 @@
|
|
|
50
56
|
"maximum": 65535,
|
|
51
57
|
"description": "Forge server port. Override this when your local machine uses a different port."
|
|
52
58
|
},
|
|
59
|
+
"dataRoot": {
|
|
60
|
+
"type": "string",
|
|
61
|
+
"default": "",
|
|
62
|
+
"description": "Optional absolute path for the Forge data folder root. Leave blank to use the runtime working directory."
|
|
63
|
+
},
|
|
53
64
|
"apiToken": {
|
|
54
65
|
"type": "string",
|
|
55
66
|
"default": "",
|
package/package.json
CHANGED
|
@@ -331,3 +331,81 @@ CREATE INDEX IF NOT EXISTS idx_session_events_session ON session_events(session_
|
|
|
331
331
|
CREATE INDEX IF NOT EXISTS idx_session_events_type ON session_events(event_type, created_at DESC);
|
|
332
332
|
CREATE INDEX IF NOT EXISTS idx_operator_sessions_active
|
|
333
333
|
ON operator_sessions(revoked_at, expires_at, last_used_at DESC);
|
|
334
|
+
|
|
335
|
+
ALTER TABLE task_runs ADD COLUMN timer_mode TEXT NOT NULL DEFAULT 'unlimited';
|
|
336
|
+
ALTER TABLE task_runs ADD COLUMN planned_duration_seconds INTEGER;
|
|
337
|
+
ALTER TABLE task_runs ADD COLUMN is_current INTEGER NOT NULL DEFAULT 0;
|
|
338
|
+
|
|
339
|
+
UPDATE task_runs
|
|
340
|
+
SET timer_mode = 'unlimited',
|
|
341
|
+
planned_duration_seconds = NULL
|
|
342
|
+
WHERE timer_mode IS NULL OR timer_mode = '';
|
|
343
|
+
|
|
344
|
+
ALTER TABLE app_settings ADD COLUMN max_active_tasks INTEGER NOT NULL DEFAULT 2;
|
|
345
|
+
ALTER TABLE app_settings ADD COLUMN time_accounting_mode TEXT NOT NULL DEFAULT 'split';
|
|
346
|
+
ALTER TABLE app_settings ADD COLUMN psyche_auth_required INTEGER NOT NULL DEFAULT 0;
|
|
347
|
+
|
|
348
|
+
CREATE INDEX IF NOT EXISTS idx_task_runs_actor_status_claimed
|
|
349
|
+
ON task_runs(actor, status, claimed_at);
|
|
350
|
+
|
|
351
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_task_runs_single_current_per_actor
|
|
352
|
+
ON task_runs(actor)
|
|
353
|
+
WHERE status = 'active' AND is_current = 1;
|
|
354
|
+
|
|
355
|
+
CREATE TABLE deleted_entities (
|
|
356
|
+
entity_type TEXT NOT NULL,
|
|
357
|
+
entity_id TEXT NOT NULL,
|
|
358
|
+
title TEXT NOT NULL,
|
|
359
|
+
subtitle TEXT NOT NULL DEFAULT '',
|
|
360
|
+
deleted_at TEXT NOT NULL,
|
|
361
|
+
deleted_by_actor TEXT,
|
|
362
|
+
deleted_source TEXT NOT NULL,
|
|
363
|
+
delete_reason TEXT NOT NULL DEFAULT '',
|
|
364
|
+
snapshot_json TEXT NOT NULL,
|
|
365
|
+
PRIMARY KEY (entity_type, entity_id)
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
CREATE INDEX idx_deleted_entities_deleted_at
|
|
369
|
+
ON deleted_entities (deleted_at DESC);
|
|
370
|
+
|
|
371
|
+
CREATE TABLE IF NOT EXISTS notes (
|
|
372
|
+
id TEXT PRIMARY KEY,
|
|
373
|
+
content_markdown TEXT NOT NULL,
|
|
374
|
+
content_plain TEXT NOT NULL DEFAULT '',
|
|
375
|
+
author TEXT,
|
|
376
|
+
source TEXT NOT NULL,
|
|
377
|
+
created_at TEXT NOT NULL,
|
|
378
|
+
updated_at TEXT NOT NULL
|
|
379
|
+
);
|
|
380
|
+
|
|
381
|
+
CREATE TABLE IF NOT EXISTS note_links (
|
|
382
|
+
note_id TEXT NOT NULL,
|
|
383
|
+
entity_type TEXT NOT NULL,
|
|
384
|
+
entity_id TEXT NOT NULL,
|
|
385
|
+
anchor_key TEXT NOT NULL DEFAULT '',
|
|
386
|
+
created_at TEXT NOT NULL,
|
|
387
|
+
PRIMARY KEY (note_id, entity_type, entity_id, anchor_key),
|
|
388
|
+
FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE CASCADE
|
|
389
|
+
);
|
|
390
|
+
|
|
391
|
+
CREATE INDEX IF NOT EXISTS idx_note_links_target
|
|
392
|
+
ON note_links (entity_type, entity_id, created_at DESC);
|
|
393
|
+
|
|
394
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS notes_fts
|
|
395
|
+
USING fts5(
|
|
396
|
+
note_id UNINDEXED,
|
|
397
|
+
content_plain,
|
|
398
|
+
author
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
INSERT INTO notes_fts (note_id, content_plain, author)
|
|
402
|
+
SELECT
|
|
403
|
+
notes.id,
|
|
404
|
+
notes.content_plain,
|
|
405
|
+
COALESCE(notes.author, '')
|
|
406
|
+
FROM notes
|
|
407
|
+
WHERE NOT EXISTS (
|
|
408
|
+
SELECT 1
|
|
409
|
+
FROM notes_fts
|
|
410
|
+
WHERE notes_fts.note_id = notes.id
|
|
411
|
+
);
|