rolexjs 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +347 -97
- package/dist/index.d.ts +269 -23
- package/dist/index.js +681 -333
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -1,8 +1,332 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
export * from "@rolexjs/core";
|
|
3
3
|
|
|
4
|
+
// src/context.ts
|
|
5
|
+
var RoleContext = class {
|
|
6
|
+
roleId;
|
|
7
|
+
focusedGoalId = null;
|
|
8
|
+
focusedPlanId = null;
|
|
9
|
+
encounterIds = /* @__PURE__ */ new Set();
|
|
10
|
+
experienceIds = /* @__PURE__ */ new Set();
|
|
11
|
+
constructor(roleId) {
|
|
12
|
+
this.roleId = roleId;
|
|
13
|
+
}
|
|
14
|
+
// ================================================================
|
|
15
|
+
// Requirements — throw if missing
|
|
16
|
+
// ================================================================
|
|
17
|
+
requireGoalId() {
|
|
18
|
+
if (!this.focusedGoalId) throw new Error("No focused goal. Call want first.");
|
|
19
|
+
return this.focusedGoalId;
|
|
20
|
+
}
|
|
21
|
+
requirePlanId() {
|
|
22
|
+
if (!this.focusedPlanId) throw new Error("No focused plan. Call plan first.");
|
|
23
|
+
return this.focusedPlanId;
|
|
24
|
+
}
|
|
25
|
+
// ================================================================
|
|
26
|
+
// Cognition registries
|
|
27
|
+
// ================================================================
|
|
28
|
+
addEncounter(id) {
|
|
29
|
+
this.encounterIds.add(id);
|
|
30
|
+
}
|
|
31
|
+
requireEncounterIds(ids) {
|
|
32
|
+
for (const id of ids) {
|
|
33
|
+
if (!this.encounterIds.has(id)) throw new Error(`Encounter not found: "${id}"`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
consumeEncounters(ids) {
|
|
37
|
+
for (const id of ids) {
|
|
38
|
+
this.encounterIds.delete(id);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
addExperience(id) {
|
|
42
|
+
this.experienceIds.add(id);
|
|
43
|
+
}
|
|
44
|
+
requireExperienceIds(ids) {
|
|
45
|
+
for (const id of ids) {
|
|
46
|
+
if (!this.experienceIds.has(id)) throw new Error(`Experience not found: "${id}"`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
consumeExperiences(ids) {
|
|
50
|
+
for (const id of ids) {
|
|
51
|
+
this.experienceIds.delete(id);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// ================================================================
|
|
55
|
+
// Rehydration — rebuild from activation state
|
|
56
|
+
// ================================================================
|
|
57
|
+
/** Walk the state tree and populate registries. */
|
|
58
|
+
rehydrate(state) {
|
|
59
|
+
this.walk(state);
|
|
60
|
+
}
|
|
61
|
+
walk(node) {
|
|
62
|
+
if (node.id) {
|
|
63
|
+
switch (node.name) {
|
|
64
|
+
case "goal":
|
|
65
|
+
if (!this.focusedGoalId) this.focusedGoalId = node.id;
|
|
66
|
+
break;
|
|
67
|
+
case "encounter":
|
|
68
|
+
this.encounterIds.add(node.id);
|
|
69
|
+
break;
|
|
70
|
+
case "experience":
|
|
71
|
+
this.experienceIds.add(node.id);
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
for (const child of node.children ?? []) {
|
|
76
|
+
this.walk(child);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// ================================================================
|
|
80
|
+
// Cognitive hints — state-aware AI self-direction cues
|
|
81
|
+
// ================================================================
|
|
82
|
+
/** First-person, state-aware hint for the AI after an operation. */
|
|
83
|
+
cognitiveHint(process) {
|
|
84
|
+
switch (process) {
|
|
85
|
+
case "activate":
|
|
86
|
+
if (!this.focusedGoalId)
|
|
87
|
+
return "I have no goal yet. I should call `want` to declare one, or `focus` to review existing goals.";
|
|
88
|
+
return "I have an active goal. I should call `focus` to review progress, or `want` to declare a new goal.";
|
|
89
|
+
case "focus":
|
|
90
|
+
if (!this.focusedPlanId)
|
|
91
|
+
return "I have a goal but no focused plan. I should call `plan` to create or focus on one.";
|
|
92
|
+
return "I have a plan. I should call `todo` to create tasks, or continue working.";
|
|
93
|
+
case "want":
|
|
94
|
+
return "Goal declared. I should call `plan` to design how to achieve it.";
|
|
95
|
+
case "plan":
|
|
96
|
+
return "Plan created. I should call `todo` to create concrete tasks.";
|
|
97
|
+
case "todo":
|
|
98
|
+
return "Task created. I can add more with `todo`, or start working and call `finish` when done.";
|
|
99
|
+
case "finish": {
|
|
100
|
+
const encCount = this.encounterIds.size;
|
|
101
|
+
if (encCount > 0 && !this.focusedGoalId)
|
|
102
|
+
return `Task finished. No more goals \u2014 I have ${encCount} encounter(s) to choose from for \`reflect\`, or \`want\` a new goal.`;
|
|
103
|
+
return "Task finished. I should continue with remaining tasks, or call `complete` when the plan is done.";
|
|
104
|
+
}
|
|
105
|
+
case "complete":
|
|
106
|
+
case "abandon": {
|
|
107
|
+
const encCount = this.encounterIds.size;
|
|
108
|
+
const goalNote = this.focusedGoalId ? ` I should check if goal "${this.focusedGoalId}" needs a new \`plan\`, or \`forget\` it if the direction is fulfilled.` : "";
|
|
109
|
+
if (encCount > 0)
|
|
110
|
+
return `Plan closed.${goalNote} I have ${encCount} encounter(s) to choose from for \`reflect\`, or I can continue with other plans.`;
|
|
111
|
+
return `Plan closed.${goalNote} I can create a new \`plan\`, or \`focus\` on another goal.`;
|
|
112
|
+
}
|
|
113
|
+
case "reflect": {
|
|
114
|
+
const expCount = this.experienceIds.size;
|
|
115
|
+
if (expCount > 0)
|
|
116
|
+
return `Experience gained. I can \`realize\` principles or \`master\` procedures \u2014 ${expCount} experience(s) available.`;
|
|
117
|
+
return "Experience gained. I can `realize` a principle, `master` a procedure, or continue working.";
|
|
118
|
+
}
|
|
119
|
+
case "realize":
|
|
120
|
+
return "Principle added. I should continue working.";
|
|
121
|
+
case "master":
|
|
122
|
+
return "Procedure added. I should continue working.";
|
|
123
|
+
default:
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// src/feature.ts
|
|
130
|
+
import { parse as parseGherkin } from "@rolexjs/parser";
|
|
131
|
+
function parse(source) {
|
|
132
|
+
const doc = parseGherkin(source);
|
|
133
|
+
const f = doc.feature;
|
|
134
|
+
if (!f) throw new Error("No Feature found in source");
|
|
135
|
+
return {
|
|
136
|
+
name: f.name,
|
|
137
|
+
...f.description?.trim() ? { description: f.description.trim() } : {},
|
|
138
|
+
...f.tags?.length ? { tags: f.tags.map((t) => t.name) } : {},
|
|
139
|
+
scenarios: (f.children ?? []).filter((c) => c.scenario).map((c) => {
|
|
140
|
+
const s = c.scenario;
|
|
141
|
+
return {
|
|
142
|
+
name: s.name,
|
|
143
|
+
...s.description?.trim() ? { description: s.description.trim() } : {},
|
|
144
|
+
...s.tags?.length ? { tags: s.tags.map((t) => t.name) } : {},
|
|
145
|
+
steps: (s.steps ?? []).map((st) => ({
|
|
146
|
+
keyword: st.keyword,
|
|
147
|
+
text: st.text,
|
|
148
|
+
...st.dataTable ? {
|
|
149
|
+
dataTable: st.dataTable.rows.map((r) => ({
|
|
150
|
+
cells: r.cells.map((c2) => c2.value)
|
|
151
|
+
}))
|
|
152
|
+
} : {}
|
|
153
|
+
}))
|
|
154
|
+
};
|
|
155
|
+
})
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function serialize(feature) {
|
|
159
|
+
const lines = [];
|
|
160
|
+
if (feature.tags?.length) {
|
|
161
|
+
lines.push(feature.tags.join(" "));
|
|
162
|
+
}
|
|
163
|
+
lines.push(`Feature: ${feature.name}`);
|
|
164
|
+
if (feature.description) {
|
|
165
|
+
for (const line of feature.description.split("\n")) {
|
|
166
|
+
lines.push(` ${line}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
for (const scenario of feature.scenarios) {
|
|
170
|
+
lines.push("");
|
|
171
|
+
if (scenario.tags?.length) {
|
|
172
|
+
lines.push(` ${scenario.tags.join(" ")}`);
|
|
173
|
+
}
|
|
174
|
+
lines.push(` Scenario: ${scenario.name}`);
|
|
175
|
+
if (scenario.description) {
|
|
176
|
+
for (const line of scenario.description.split("\n")) {
|
|
177
|
+
lines.push(` ${line}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
for (const step of scenario.steps) {
|
|
181
|
+
lines.push(` ${step.keyword}${step.text}`);
|
|
182
|
+
if (step.dataTable) {
|
|
183
|
+
for (const row of step.dataTable) {
|
|
184
|
+
lines.push(` | ${row.cells.join(" | ")} |`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return `${lines.join("\n")}
|
|
190
|
+
`;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// src/find.ts
|
|
194
|
+
var PRIORITY = {
|
|
195
|
+
individual: 0,
|
|
196
|
+
organization: 0,
|
|
197
|
+
position: 0,
|
|
198
|
+
goal: 1,
|
|
199
|
+
plan: 2,
|
|
200
|
+
task: 2,
|
|
201
|
+
procedure: 3,
|
|
202
|
+
principle: 3,
|
|
203
|
+
encounter: 4,
|
|
204
|
+
experience: 4,
|
|
205
|
+
identity: 5,
|
|
206
|
+
charter: 5,
|
|
207
|
+
duty: 6,
|
|
208
|
+
requirement: 6,
|
|
209
|
+
background: 6,
|
|
210
|
+
tone: 6,
|
|
211
|
+
mindset: 6
|
|
212
|
+
};
|
|
213
|
+
function priorityOf(name) {
|
|
214
|
+
return PRIORITY[name] ?? 7;
|
|
215
|
+
}
|
|
216
|
+
function matches(node, target) {
|
|
217
|
+
if (node.id?.toLowerCase() === target) return true;
|
|
218
|
+
if (node.alias) {
|
|
219
|
+
for (const a of node.alias) {
|
|
220
|
+
if (a.toLowerCase() === target) return true;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
function findInState(state, target) {
|
|
226
|
+
const lowered = target.toLowerCase();
|
|
227
|
+
let best = null;
|
|
228
|
+
let bestPriority = Infinity;
|
|
229
|
+
function walk(node) {
|
|
230
|
+
if (matches(node, lowered)) {
|
|
231
|
+
const p = priorityOf(node.name);
|
|
232
|
+
if (p < bestPriority) {
|
|
233
|
+
best = node;
|
|
234
|
+
bestPriority = p;
|
|
235
|
+
if (p === 0) return;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
for (const child of node.children ?? []) {
|
|
239
|
+
walk(child);
|
|
240
|
+
if (bestPriority === 0) return;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
walk(state);
|
|
244
|
+
return best;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// src/issue-render.ts
|
|
248
|
+
function renderIssue(issue, labelNames) {
|
|
249
|
+
const lines = [];
|
|
250
|
+
lines.push(`#${issue.number} ${issue.title} [${issue.status}]`);
|
|
251
|
+
const meta = [`Author: ${issue.author}`];
|
|
252
|
+
if (issue.assignee) meta.push(`Assignee: ${issue.assignee}`);
|
|
253
|
+
if (labelNames && labelNames.length > 0) {
|
|
254
|
+
meta.push(`Labels: ${labelNames.join(", ")}`);
|
|
255
|
+
}
|
|
256
|
+
lines.push(meta.join(" | "));
|
|
257
|
+
if (issue.body) {
|
|
258
|
+
lines.push("\u2500\u2500\u2500");
|
|
259
|
+
lines.push(issue.body);
|
|
260
|
+
}
|
|
261
|
+
return lines.join("\n");
|
|
262
|
+
}
|
|
263
|
+
function renderIssueList(issues) {
|
|
264
|
+
if (issues.length === 0) return "No issues found.";
|
|
265
|
+
const lines = [];
|
|
266
|
+
for (const issue of issues) {
|
|
267
|
+
const assignee = issue.assignee ? ` \u2192 ${issue.assignee}` : "";
|
|
268
|
+
lines.push(`#${issue.number} [${issue.status}] ${issue.title} (${issue.author}${assignee})`);
|
|
269
|
+
}
|
|
270
|
+
return lines.join("\n");
|
|
271
|
+
}
|
|
272
|
+
function renderComment(comment) {
|
|
273
|
+
const time = formatTime(comment.createdAt);
|
|
274
|
+
return `${comment.author} (${time}):
|
|
275
|
+
${comment.body}`;
|
|
276
|
+
}
|
|
277
|
+
function renderCommentList(comments) {
|
|
278
|
+
if (comments.length === 0) return "No comments.";
|
|
279
|
+
return comments.map(renderComment).join("\n\u2500\u2500\u2500\n");
|
|
280
|
+
}
|
|
281
|
+
var statusTemplates = {
|
|
282
|
+
publish: (i) => `Issue #${i.number} created.`,
|
|
283
|
+
close: (i) => `Issue #${i.number} closed.`,
|
|
284
|
+
reopen: (i) => `Issue #${i.number} reopened.`,
|
|
285
|
+
update: (i) => `Issue #${i.number} updated.`,
|
|
286
|
+
assign: (i) => `Issue #${i.number} assigned to ${i.assignee ?? "nobody"}.`,
|
|
287
|
+
comment: (i) => `Comment added to #${i.number}.`,
|
|
288
|
+
label: (i) => `Label added to #${i.number}.`,
|
|
289
|
+
unlabel: (i) => `Label removed from #${i.number}.`
|
|
290
|
+
};
|
|
291
|
+
async function renderIssueResult(action, result, resolveLabels) {
|
|
292
|
+
switch (action) {
|
|
293
|
+
case "list":
|
|
294
|
+
return renderIssueList(result);
|
|
295
|
+
case "comments":
|
|
296
|
+
return renderCommentList(result);
|
|
297
|
+
case "comment": {
|
|
298
|
+
const comment = result;
|
|
299
|
+
return `Comment added to issue.
|
|
300
|
+
|
|
301
|
+
${renderComment(comment)}`;
|
|
302
|
+
}
|
|
303
|
+
case "get": {
|
|
304
|
+
if (!result) return "Issue not found.";
|
|
305
|
+
const issue = result;
|
|
306
|
+
const labelNames = await resolveLabelNames(issue, resolveLabels);
|
|
307
|
+
return renderIssue(issue, labelNames);
|
|
308
|
+
}
|
|
309
|
+
default: {
|
|
310
|
+
const issue = result;
|
|
311
|
+
const labelNames = await resolveLabelNames(issue, resolveLabels);
|
|
312
|
+
const status = statusTemplates[action]?.(issue) ?? `Issue #${issue.number} ${action}.`;
|
|
313
|
+
return `${status}
|
|
314
|
+
|
|
315
|
+
${renderIssue(issue, labelNames)}`;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
function formatTime(iso) {
|
|
320
|
+
return iso.replace("T", " ").replace(/\.\d+Z$/, "");
|
|
321
|
+
}
|
|
322
|
+
async function resolveLabelNames(issue, resolveLabels) {
|
|
323
|
+
if (!issue.labels || issue.labels.length === 0) return void 0;
|
|
324
|
+
if (!resolveLabels) return void 0;
|
|
325
|
+
return resolveLabels(issue.labels);
|
|
326
|
+
}
|
|
327
|
+
|
|
4
328
|
// src/render.ts
|
|
5
|
-
import { directives, processes, world } from "@rolexjs/
|
|
329
|
+
import { directives, processes, world } from "@rolexjs/prototype";
|
|
6
330
|
var descriptions = {
|
|
7
331
|
// Lifecycle
|
|
8
332
|
born: (n) => `Individual "${n}" is born.`,
|
|
@@ -30,20 +354,6 @@ var descriptions = {
|
|
|
30
354
|
deliver: (n) => `Deliverable "${n}" added.`,
|
|
31
355
|
wiki: (n) => `Wiki entry "${n}" added.`,
|
|
32
356
|
archive: (n) => `Project "${n}" archived.`,
|
|
33
|
-
produce: (n) => `Product "${n}" produced.`,
|
|
34
|
-
// Product
|
|
35
|
-
strategy: (n) => `Strategy defined for "${n}".`,
|
|
36
|
-
spec: (n) => `Spec "${n}" added.`,
|
|
37
|
-
release: (n) => `Release "${n}" published.`,
|
|
38
|
-
channel: (n) => `Channel "${n}" added.`,
|
|
39
|
-
own: (n) => `Owner assigned to "${n}".`,
|
|
40
|
-
disown: (n) => `Owner removed from "${n}".`,
|
|
41
|
-
deprecate: (n) => `Product "${n}" deprecated.`,
|
|
42
|
-
// Society
|
|
43
|
-
crown: (n) => `"${n}" crowned \u2014 sovereign permissions granted.`,
|
|
44
|
-
uncrown: (n) => `"${n}" uncrowned \u2014 sovereign permissions revoked.`,
|
|
45
|
-
// Top-level perception
|
|
46
|
-
inspect: (n) => `Inspecting "${n}".`,
|
|
47
357
|
// Role
|
|
48
358
|
activate: (n) => `Role "${n}" activated.`,
|
|
49
359
|
focus: (n) => `Focused on goal "${n}".`,
|
|
@@ -92,20 +402,6 @@ var hints = {
|
|
|
92
402
|
deliver: "deliverable recorded.",
|
|
93
403
|
wiki: "knowledge entry recorded.",
|
|
94
404
|
archive: "the project is archived.",
|
|
95
|
-
produce: "define strategy, add specs, or assign an owner.",
|
|
96
|
-
// Product
|
|
97
|
-
strategy: "add behavior specs (BDD contracts) for the product.",
|
|
98
|
-
spec: "add more specs, or publish a release.",
|
|
99
|
-
release: "add distribution channels, or continue adding specs.",
|
|
100
|
-
channel: "distribution channel recorded.",
|
|
101
|
-
own: "the individual is now the product owner.",
|
|
102
|
-
disown: "the individual is no longer the product owner.",
|
|
103
|
-
deprecate: "the product is deprecated.",
|
|
104
|
-
// Society
|
|
105
|
-
crown: "the individual now has sovereign permissions over society.",
|
|
106
|
-
uncrown: "the individual no longer has sovereign permissions.",
|
|
107
|
-
// Top-level perception
|
|
108
|
-
inspect: "use inspect on child nodes for deeper detail, or activate to work as a role.",
|
|
109
405
|
// Role
|
|
110
406
|
activate: "want a goal, or check the current state.",
|
|
111
407
|
focus: "plan how to work toward it, or add tasks.",
|
|
@@ -127,13 +423,19 @@ function hint(process) {
|
|
|
127
423
|
const h = hints[process];
|
|
128
424
|
return h ? `Next: ${h}` : "What would you like to do next?";
|
|
129
425
|
}
|
|
426
|
+
function detail(process) {
|
|
427
|
+
return processes[process] ?? "";
|
|
428
|
+
}
|
|
429
|
+
function directive(topic, scenario) {
|
|
430
|
+
return directives[topic]?.[scenario] ?? "";
|
|
431
|
+
}
|
|
130
432
|
function renderState(state, depth = 1, options) {
|
|
131
433
|
const lines = [];
|
|
132
434
|
const level = Math.min(depth, 6);
|
|
133
435
|
const heading = "#".repeat(level);
|
|
134
436
|
const idPart = state.id ? ` (${state.id})` : "";
|
|
135
437
|
const originPart = state.origin ? ` {${state.origin}}` : "";
|
|
136
|
-
const tagPart = state.
|
|
438
|
+
const tagPart = state.tag ? ` #${state.tag}` : "";
|
|
137
439
|
const progressPart = state.name === "goal" ? goalProgress(state) : "";
|
|
138
440
|
lines.push(`${heading} [${state.name}]${idPart}${originPart}${tagPart}${progressPart}`);
|
|
139
441
|
if (options?.fold?.(state)) {
|
|
@@ -145,12 +447,11 @@ function renderState(state, depth = 1, options) {
|
|
|
145
447
|
}
|
|
146
448
|
if (state.links && state.links.length > 0) {
|
|
147
449
|
const compactRelations = /* @__PURE__ */ new Set(["after", "before", "fallback", "fallback-for"]);
|
|
148
|
-
const
|
|
149
|
-
const
|
|
150
|
-
const expanded = allCompact ? [] : state.links.filter((l) => !compactRelations.has(l.relation));
|
|
450
|
+
const compact = state.links.filter((l) => compactRelations.has(l.relation));
|
|
451
|
+
const expanded = state.links.filter((l) => !compactRelations.has(l.relation));
|
|
151
452
|
for (const link of compact) {
|
|
152
453
|
const targetId = link.target.id ? ` (${link.target.id})` : "";
|
|
153
|
-
const targetTag = link.target.
|
|
454
|
+
const targetTag = link.target.tag ? ` #${link.target.tag}` : "";
|
|
154
455
|
lines.push(`> ${link.relation}: [${link.target.name}]${targetId}${targetTag}`);
|
|
155
456
|
}
|
|
156
457
|
if (expanded.length > 0) {
|
|
@@ -170,41 +471,6 @@ function renderState(state, depth = 1, options) {
|
|
|
170
471
|
}
|
|
171
472
|
return lines.join("\n");
|
|
172
473
|
}
|
|
173
|
-
function collectPermissions(state) {
|
|
174
|
-
const seen = /* @__PURE__ */ new Set();
|
|
175
|
-
const result = [];
|
|
176
|
-
const walk = (s) => {
|
|
177
|
-
if (s.links) {
|
|
178
|
-
for (const link of s.links) {
|
|
179
|
-
if (link.permissions) {
|
|
180
|
-
for (const p of link.permissions) {
|
|
181
|
-
if (!seen.has(p.command)) {
|
|
182
|
-
seen.add(p.command);
|
|
183
|
-
result.push(p);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
if (s.children) {
|
|
190
|
-
for (const child of s.children) {
|
|
191
|
-
walk(child);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
walk(state);
|
|
196
|
-
return result;
|
|
197
|
-
}
|
|
198
|
-
function renderPermissions(permissions) {
|
|
199
|
-
if (permissions.length === 0) return "";
|
|
200
|
-
const lines = [];
|
|
201
|
-
lines.push("# Permissions\n");
|
|
202
|
-
for (const p of permissions) {
|
|
203
|
-
lines.push(p.content);
|
|
204
|
-
lines.push("");
|
|
205
|
-
}
|
|
206
|
-
return lines.join("\n");
|
|
207
|
-
}
|
|
208
474
|
var CONCEPT_ORDER = [
|
|
209
475
|
// Individual — Identity
|
|
210
476
|
"identity",
|
|
@@ -230,12 +496,7 @@ var CONCEPT_ORDER = [
|
|
|
230
496
|
"scope",
|
|
231
497
|
"milestone",
|
|
232
498
|
"deliverable",
|
|
233
|
-
"wiki"
|
|
234
|
-
// Product
|
|
235
|
-
"strategy",
|
|
236
|
-
"spec",
|
|
237
|
-
"release",
|
|
238
|
-
"channel"
|
|
499
|
+
"wiki"
|
|
239
500
|
];
|
|
240
501
|
function goalProgress(goal) {
|
|
241
502
|
let plans = 0;
|
|
@@ -245,10 +506,10 @@ function goalProgress(goal) {
|
|
|
245
506
|
function walk(node) {
|
|
246
507
|
if (node.name === "plan") {
|
|
247
508
|
plans++;
|
|
248
|
-
if (node.
|
|
509
|
+
if (node.tag === "done" || node.tag === "abandoned") plansDone++;
|
|
249
510
|
} else if (node.name === "task") {
|
|
250
511
|
tasks++;
|
|
251
|
-
if (node.
|
|
512
|
+
if (node.tag === "done") tasksDone++;
|
|
252
513
|
}
|
|
253
514
|
for (const child of node.children ?? []) walk(child);
|
|
254
515
|
}
|
|
@@ -271,92 +532,25 @@ function sortByConceptOrder(children) {
|
|
|
271
532
|
return aOrder - bOrder;
|
|
272
533
|
});
|
|
273
534
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
function renderProduct(state) {
|
|
277
|
-
const lines = [];
|
|
278
|
-
const id = state.id ?? "(no id)";
|
|
279
|
-
const tagPart = state.tags?.length ? ` ${state.tags.map((t) => `#${t}`).join(" ")}` : "";
|
|
280
|
-
lines.push(`# ${id}${tagPart}`);
|
|
281
|
-
if (state.information) {
|
|
282
|
-
lines.push("");
|
|
283
|
-
lines.push(state.information);
|
|
284
|
-
}
|
|
285
|
-
const owners = state.links?.filter((l) => l.relation === "ownership") ?? [];
|
|
286
|
-
if (owners.length > 0) {
|
|
287
|
-
lines.push("");
|
|
288
|
-
lines.push("## Owner");
|
|
289
|
-
for (const o of owners) {
|
|
290
|
-
const alias = Array.isArray(o.target.alias) && o.target.alias.length ? ` (${o.target.alias.join(", ")})` : "";
|
|
291
|
-
lines.push(`- ${o.target.id ?? "(no id)"}${alias}`);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
const children = state.children ?? [];
|
|
295
|
-
const strategies = children.filter((c) => c.name === "strategy");
|
|
296
|
-
const specs = children.filter((c) => c.name === "spec");
|
|
297
|
-
const releases = children.filter((c) => c.name === "release");
|
|
298
|
-
const channels = children.filter((c) => c.name === "channel");
|
|
299
|
-
if (strategies.length > 0) {
|
|
300
|
-
lines.push("");
|
|
301
|
-
lines.push("## Strategy");
|
|
302
|
-
for (const s of strategies) {
|
|
303
|
-
if (s.information) lines.push(s.information);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
if (specs.length > 0) {
|
|
307
|
-
lines.push("");
|
|
308
|
-
lines.push("## Specs");
|
|
309
|
-
for (const s of specs) {
|
|
310
|
-
const title = s.id ?? extractFeatureTitle(s.information);
|
|
311
|
-
lines.push(`- ${title}`);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
if (releases.length > 0) {
|
|
315
|
-
lines.push("");
|
|
316
|
-
lines.push("## Releases");
|
|
317
|
-
for (const r of releases) {
|
|
318
|
-
const rTag = r.tags?.length ? ` ${r.tags.map((t) => `#${t}`).join(" ")}` : "";
|
|
319
|
-
const title = r.id ?? extractFeatureTitle(r.information);
|
|
320
|
-
lines.push(`- ${title}${rTag}`);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
if (channels.length > 0) {
|
|
324
|
-
lines.push("");
|
|
325
|
-
lines.push("## Channels");
|
|
326
|
-
for (const c of channels) {
|
|
327
|
-
const title = c.id ?? extractFeatureTitle(c.information);
|
|
328
|
-
lines.push(`- ${title}`);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
return lines.join("\n");
|
|
332
|
-
}
|
|
333
|
-
function renderProductResult(action, state) {
|
|
334
|
-
const name = state.id ?? state.name;
|
|
535
|
+
function render(opts) {
|
|
536
|
+
const { process, name, state, cognitiveHint, fold } = opts;
|
|
335
537
|
const lines = [];
|
|
336
|
-
lines.push(describe(
|
|
337
|
-
lines.push(hint(
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
lines.push("");
|
|
341
|
-
lines.push(renderProduct(productState));
|
|
538
|
+
lines.push(describe(process, name, state));
|
|
539
|
+
lines.push(hint(process));
|
|
540
|
+
if (cognitiveHint) {
|
|
541
|
+
lines.push(`I \u2192 ${cognitiveHint}`);
|
|
342
542
|
}
|
|
543
|
+
lines.push("");
|
|
544
|
+
lines.push(renderState(state, 1, fold ? { fold } : void 0));
|
|
343
545
|
return lines.join("\n");
|
|
344
546
|
}
|
|
345
|
-
function isProductNode(state) {
|
|
346
|
-
return state.name === "product";
|
|
347
|
-
}
|
|
348
|
-
function extractFeatureTitle(information) {
|
|
349
|
-
if (!information) return "(untitled)";
|
|
350
|
-
const match = information.match(/^Feature:\s*(.+)$/m);
|
|
351
|
-
return match?.[1]?.trim() ?? information.split("\n")[0].trim();
|
|
352
|
-
}
|
|
353
547
|
|
|
354
548
|
// src/project-render.ts
|
|
355
549
|
function renderProject(state) {
|
|
356
550
|
const lines = [];
|
|
357
551
|
const id = state.id ?? "(no id)";
|
|
358
|
-
const
|
|
359
|
-
lines.push(`# ${id}${
|
|
552
|
+
const tag = state.tag ? ` #${state.tag}` : "";
|
|
553
|
+
lines.push(`# ${id}${tag}`);
|
|
360
554
|
if (state.information) {
|
|
361
555
|
lines.push("");
|
|
362
556
|
lines.push(state.information);
|
|
@@ -366,7 +560,7 @@ function renderProject(state) {
|
|
|
366
560
|
lines.push("");
|
|
367
561
|
lines.push("## Members");
|
|
368
562
|
for (const m of members) {
|
|
369
|
-
const alias =
|
|
563
|
+
const alias = m.target.alias?.length ? ` (${m.target.alias.join(", ")})` : "";
|
|
370
564
|
lines.push(`- ${m.target.id ?? "(no id)"}${alias}`);
|
|
371
565
|
}
|
|
372
566
|
}
|
|
@@ -386,12 +580,12 @@ function renderProject(state) {
|
|
|
386
580
|
lines.push("");
|
|
387
581
|
lines.push("## Milestones");
|
|
388
582
|
for (const m of milestones) {
|
|
389
|
-
const
|
|
390
|
-
const marker = m.
|
|
391
|
-
const title =
|
|
392
|
-
lines.push(`- ${marker} ${m.id ?? title}${
|
|
583
|
+
const tag2 = m.tag ? ` #${m.tag}` : "";
|
|
584
|
+
const marker = m.tag === "done" ? "[x]" : "[ ]";
|
|
585
|
+
const title = extractFeatureTitle(m.information);
|
|
586
|
+
lines.push(`- ${marker} ${m.id ?? title}${tag2}`);
|
|
393
587
|
if (m.information && m.id) {
|
|
394
|
-
const desc =
|
|
588
|
+
const desc = extractFeatureTitle(m.information);
|
|
395
589
|
if (desc && desc !== m.id) lines.push(` ${desc}`);
|
|
396
590
|
}
|
|
397
591
|
}
|
|
@@ -400,7 +594,7 @@ function renderProject(state) {
|
|
|
400
594
|
lines.push("");
|
|
401
595
|
lines.push("## Deliverables");
|
|
402
596
|
for (const d of deliverables) {
|
|
403
|
-
const title = d.id ??
|
|
597
|
+
const title = d.id ?? extractFeatureTitle(d.information);
|
|
404
598
|
lines.push(`- ${title}`);
|
|
405
599
|
}
|
|
406
600
|
}
|
|
@@ -408,7 +602,7 @@ function renderProject(state) {
|
|
|
408
602
|
lines.push("");
|
|
409
603
|
lines.push("## Wiki");
|
|
410
604
|
for (const w of wikis) {
|
|
411
|
-
const title = w.id ??
|
|
605
|
+
const title = w.id ?? extractFeatureTitle(w.information);
|
|
412
606
|
lines.push(`- ${title}`);
|
|
413
607
|
}
|
|
414
608
|
}
|
|
@@ -429,207 +623,361 @@ function renderProjectResult(action, state) {
|
|
|
429
623
|
function isProjectNode(state) {
|
|
430
624
|
return state.name === "project";
|
|
431
625
|
}
|
|
432
|
-
function
|
|
626
|
+
function extractFeatureTitle(information) {
|
|
433
627
|
if (!information) return "(untitled)";
|
|
434
628
|
const match = information.match(/^Feature:\s*(.+)$/m);
|
|
435
629
|
return match?.[1]?.trim() ?? information.split("\n")[0].trim();
|
|
436
630
|
}
|
|
437
631
|
|
|
438
|
-
// src/
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
render(_command, result) {
|
|
448
|
-
const name = result.state.id ?? result.state.name;
|
|
449
|
-
const lines = [];
|
|
450
|
-
lines.push(describe(result.process, name, result.state));
|
|
451
|
-
lines.push(hint(result.process));
|
|
452
|
-
lines.push("");
|
|
453
|
-
lines.push(renderState(result.state, 1, { compactLinks: true }));
|
|
454
|
-
return lines.join("\n");
|
|
632
|
+
// src/role.ts
|
|
633
|
+
var Role = class {
|
|
634
|
+
roleId;
|
|
635
|
+
ctx;
|
|
636
|
+
api;
|
|
637
|
+
constructor(roleId, ctx, api) {
|
|
638
|
+
this.roleId = roleId;
|
|
639
|
+
this.ctx = ctx;
|
|
640
|
+
this.api = api;
|
|
455
641
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
const lines = [];
|
|
464
|
-
lines.push(describe(process, name, result.state));
|
|
465
|
-
lines.push(hint(process));
|
|
466
|
-
lines.push("");
|
|
467
|
-
lines.push(renderState(result.state));
|
|
468
|
-
return lines.join("\n");
|
|
642
|
+
/** Project the individual's full state tree (used after activate). */
|
|
643
|
+
async project() {
|
|
644
|
+
const result = await this.api.ops["role.focus"](this.roleId);
|
|
645
|
+
const focusedGoalId = this.ctx.focusedGoalId;
|
|
646
|
+
return this.fmt("activate", this.roleId, result, {
|
|
647
|
+
fold: (node) => node.name === "goal" && node.id !== focusedGoalId || node.name === "requirement"
|
|
648
|
+
});
|
|
469
649
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
lines.push(hint(process));
|
|
480
|
-
lines.push("");
|
|
481
|
-
lines.push(renderState(result.state));
|
|
482
|
-
return lines.join("\n");
|
|
650
|
+
/** Render an OpResult into a 3-layer output string. */
|
|
651
|
+
fmt(process, name, result, extra) {
|
|
652
|
+
return render({
|
|
653
|
+
process,
|
|
654
|
+
name,
|
|
655
|
+
state: result.state,
|
|
656
|
+
cognitiveHint: this.ctx.cognitiveHint(process) ?? null,
|
|
657
|
+
fold: extra?.fold
|
|
658
|
+
});
|
|
483
659
|
}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
// src/renderers/product.ts
|
|
487
|
-
var ProductRenderer = class {
|
|
488
|
-
render(command, result) {
|
|
489
|
-
const action = command.startsWith("product.") ? command.slice("product.".length) : command;
|
|
490
|
-
return renderProductResult(action, result.state);
|
|
660
|
+
async save() {
|
|
661
|
+
await this.api.saveCtx(this.ctx);
|
|
491
662
|
}
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
663
|
+
// ---- Execution ----
|
|
664
|
+
/** Focus: view or switch focused goal. Only accepts goal ids. */
|
|
665
|
+
async focus(goal) {
|
|
666
|
+
const goalId = goal ?? this.ctx.requireGoalId();
|
|
667
|
+
const result = await this.api.ops["role.focus"](goalId);
|
|
668
|
+
if (result.state.name !== "goal") {
|
|
669
|
+
throw new Error(
|
|
670
|
+
`"${goalId}" is a ${result.state.name}, not a goal. focus only accepts goal ids.`
|
|
671
|
+
);
|
|
500
672
|
}
|
|
501
|
-
|
|
673
|
+
const switched = goalId !== this.ctx.focusedGoalId;
|
|
674
|
+
this.ctx.focusedGoalId = goalId;
|
|
675
|
+
if (switched) this.ctx.focusedPlanId = null;
|
|
676
|
+
await this.save();
|
|
677
|
+
return this.fmt("focus", goalId, result);
|
|
502
678
|
}
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
679
|
+
/** Want: declare a goal. */
|
|
680
|
+
async want(goal, id, alias) {
|
|
681
|
+
const result = await this.api.ops["role.want"](this.roleId, goal, id, alias);
|
|
682
|
+
if (id) this.ctx.focusedGoalId = id;
|
|
683
|
+
this.ctx.focusedPlanId = null;
|
|
684
|
+
await this.save();
|
|
685
|
+
return this.fmt("want", id ?? this.roleId, result);
|
|
686
|
+
}
|
|
687
|
+
/** Plan: create a plan for the focused goal. */
|
|
688
|
+
async plan(plan, id, after, fallback) {
|
|
689
|
+
const result = await this.api.ops["role.plan"](
|
|
690
|
+
this.ctx.requireGoalId(),
|
|
691
|
+
plan,
|
|
692
|
+
id,
|
|
693
|
+
after,
|
|
694
|
+
fallback
|
|
695
|
+
);
|
|
696
|
+
if (id) this.ctx.focusedPlanId = id;
|
|
697
|
+
await this.save();
|
|
698
|
+
return this.fmt("plan", id ?? "plan", result);
|
|
699
|
+
}
|
|
700
|
+
/** Todo: add a task to the focused plan. */
|
|
701
|
+
async todo(task, id, alias) {
|
|
702
|
+
const result = await this.api.ops["role.todo"](this.ctx.requirePlanId(), task, id, alias);
|
|
703
|
+
return this.fmt("todo", id ?? "task", result);
|
|
704
|
+
}
|
|
705
|
+
/** Finish: complete a task, optionally record an encounter. */
|
|
706
|
+
async finish(task, encounter) {
|
|
707
|
+
const result = await this.api.ops["role.finish"](task, this.roleId, encounter);
|
|
708
|
+
if (encounter && result.state.id) {
|
|
709
|
+
this.ctx.addEncounter(result.state.id);
|
|
710
|
+
}
|
|
711
|
+
return this.fmt("finish", task, result);
|
|
712
|
+
}
|
|
713
|
+
/** Complete: close a plan as done, record encounter. */
|
|
714
|
+
async complete(plan, encounter) {
|
|
715
|
+
const planId = plan ?? this.ctx.requirePlanId();
|
|
716
|
+
const result = await this.api.ops["role.complete"](planId, this.roleId, encounter);
|
|
717
|
+
this.ctx.addEncounter(result.state.id ?? planId);
|
|
718
|
+
if (this.ctx.focusedPlanId === planId) this.ctx.focusedPlanId = null;
|
|
719
|
+
await this.save();
|
|
720
|
+
return this.fmt("complete", planId, result);
|
|
721
|
+
}
|
|
722
|
+
/** Abandon: drop a plan, record encounter. */
|
|
723
|
+
async abandon(plan, encounter) {
|
|
724
|
+
const planId = plan ?? this.ctx.requirePlanId();
|
|
725
|
+
const result = await this.api.ops["role.abandon"](planId, this.roleId, encounter);
|
|
726
|
+
this.ctx.addEncounter(result.state.id ?? planId);
|
|
727
|
+
if (this.ctx.focusedPlanId === planId) this.ctx.focusedPlanId = null;
|
|
728
|
+
await this.save();
|
|
729
|
+
return this.fmt("abandon", planId, result);
|
|
730
|
+
}
|
|
731
|
+
// ---- Cognition ----
|
|
732
|
+
/** Reflect: consume encounters → experience. Empty encounters = direct creation. */
|
|
733
|
+
async reflect(encounters, experience, id) {
|
|
734
|
+
if (encounters.length > 0) {
|
|
735
|
+
this.ctx.requireEncounterIds(encounters);
|
|
736
|
+
}
|
|
737
|
+
const first = encounters[0];
|
|
738
|
+
const result = await this.api.ops["role.reflect"](first, this.roleId, experience, id);
|
|
739
|
+
for (let i = 1; i < encounters.length; i++) {
|
|
740
|
+
await this.api.ops["role.forget"](encounters[i]);
|
|
741
|
+
}
|
|
742
|
+
if (encounters.length > 0) {
|
|
743
|
+
this.ctx.consumeEncounters(encounters);
|
|
744
|
+
}
|
|
745
|
+
if (id) this.ctx.addExperience(id);
|
|
746
|
+
return this.fmt("reflect", id ?? "experience", result);
|
|
747
|
+
}
|
|
748
|
+
/** Realize: consume experiences → principle. Empty experiences = direct creation. */
|
|
749
|
+
async realize(experiences, principle, id) {
|
|
750
|
+
if (experiences.length > 0) {
|
|
751
|
+
this.ctx.requireExperienceIds(experiences);
|
|
752
|
+
}
|
|
753
|
+
const first = experiences[0];
|
|
754
|
+
const result = await this.api.ops["role.realize"](first, this.roleId, principle, id);
|
|
755
|
+
for (let i = 1; i < experiences.length; i++) {
|
|
756
|
+
await this.api.ops["role.forget"](experiences[i]);
|
|
757
|
+
}
|
|
758
|
+
if (experiences.length > 0) {
|
|
759
|
+
this.ctx.consumeExperiences(experiences);
|
|
760
|
+
}
|
|
761
|
+
return this.fmt("realize", id ?? "principle", result);
|
|
762
|
+
}
|
|
763
|
+
/** Master: create procedure, optionally consuming experiences. */
|
|
764
|
+
async master(procedure, id, experiences) {
|
|
765
|
+
if (experiences && experiences.length > 0) {
|
|
766
|
+
this.ctx.requireExperienceIds(experiences);
|
|
767
|
+
}
|
|
768
|
+
const first = experiences?.[0];
|
|
769
|
+
const result = await this.api.ops["role.master"](this.roleId, procedure, id, first);
|
|
770
|
+
if (experiences) {
|
|
771
|
+
for (let i = 1; i < experiences.length; i++) {
|
|
772
|
+
await this.api.ops["role.forget"](experiences[i]);
|
|
520
773
|
}
|
|
774
|
+
this.ctx.consumeExperiences(experiences);
|
|
521
775
|
}
|
|
522
|
-
return
|
|
776
|
+
return this.fmt("master", id ?? "procedure", result);
|
|
523
777
|
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
return
|
|
778
|
+
// ---- Knowledge management ----
|
|
779
|
+
/** Forget: remove any node under the individual by id. */
|
|
780
|
+
async forget(nodeId) {
|
|
781
|
+
const result = await this.api.ops["role.forget"](nodeId);
|
|
782
|
+
if (this.ctx.focusedGoalId === nodeId) this.ctx.focusedGoalId = null;
|
|
783
|
+
if (this.ctx.focusedPlanId === nodeId) this.ctx.focusedPlanId = null;
|
|
784
|
+
await this.save();
|
|
785
|
+
return this.fmt("forget", nodeId, result);
|
|
786
|
+
}
|
|
787
|
+
// ---- Skills + unified entry ----
|
|
788
|
+
/** Skill: load full skill content by locator. */
|
|
789
|
+
async skill(locator) {
|
|
790
|
+
return await this.api.ops["role.skill"](locator);
|
|
791
|
+
}
|
|
792
|
+
/** Use: subjective execution — `!ns.method` or ResourceX locator. */
|
|
793
|
+
async use(locator, args) {
|
|
794
|
+
const result = await this.api.direct(locator, args);
|
|
795
|
+
if (locator.startsWith("!issue.")) {
|
|
796
|
+
const action = locator.slice("!issue.".length);
|
|
797
|
+
return await renderIssueResult(action, result, this.api.resolveLabels);
|
|
798
|
+
}
|
|
799
|
+
if (locator.startsWith("!project.")) {
|
|
800
|
+
const action = locator.slice("!project.".length);
|
|
801
|
+
const opResult = result;
|
|
802
|
+
return renderProjectResult(action, opResult.state);
|
|
803
|
+
}
|
|
804
|
+
return result;
|
|
537
805
|
}
|
|
538
806
|
};
|
|
539
807
|
|
|
540
|
-
// src/
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
808
|
+
// src/rolex.ts
|
|
809
|
+
import * as C from "@rolexjs/core";
|
|
810
|
+
import { createOps, directives as directives2, toArgs } from "@rolexjs/prototype";
|
|
811
|
+
import { createIssueX } from "issuexjs";
|
|
812
|
+
import { createResourceX, setProvider } from "resourcexjs";
|
|
813
|
+
var Rolex = class _Rolex {
|
|
814
|
+
rt;
|
|
815
|
+
ops;
|
|
816
|
+
resourcex;
|
|
817
|
+
issuex;
|
|
818
|
+
repo;
|
|
819
|
+
initializer;
|
|
820
|
+
bootstrap;
|
|
821
|
+
society;
|
|
822
|
+
past;
|
|
823
|
+
constructor(platform) {
|
|
824
|
+
this.repo = platform.repository;
|
|
825
|
+
this.rt = this.repo.runtime;
|
|
826
|
+
this.initializer = platform.initializer;
|
|
827
|
+
this.bootstrap = platform.bootstrap ?? [];
|
|
828
|
+
if (platform.resourcexProvider) {
|
|
829
|
+
setProvider(platform.resourcexProvider);
|
|
830
|
+
this.resourcex = createResourceX(
|
|
831
|
+
platform.resourcexExecutor ? { isolator: "custom", executor: platform.resourcexExecutor } : void 0
|
|
832
|
+
);
|
|
833
|
+
}
|
|
834
|
+
if (platform.issuexProvider) {
|
|
835
|
+
this.issuex = createIssueX({ provider: platform.issuexProvider });
|
|
559
836
|
}
|
|
560
|
-
return lines.join("\n");
|
|
561
837
|
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
const
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
838
|
+
/** Create a Rolex instance from a Platform (async due to Runtime initialization). */
|
|
839
|
+
static async create(platform) {
|
|
840
|
+
const rolex = new _Rolex(platform);
|
|
841
|
+
await rolex.init();
|
|
842
|
+
return rolex;
|
|
843
|
+
}
|
|
844
|
+
/** Async initialization — called by Rolex.create(). */
|
|
845
|
+
async init() {
|
|
846
|
+
const roots = await this.rt.roots();
|
|
847
|
+
this.society = roots.find((r) => r.name === "society") ?? await this.rt.create(null, C.society);
|
|
848
|
+
const societyState = await this.rt.project(this.society);
|
|
849
|
+
const existingPast = societyState.children?.find((c) => c.name === "past");
|
|
850
|
+
this.past = existingPast ?? await this.rt.create(this.society, C.past);
|
|
851
|
+
this.ops = createOps({
|
|
852
|
+
rt: this.rt,
|
|
853
|
+
society: this.society,
|
|
854
|
+
past: this.past,
|
|
855
|
+
resolve: async (id) => {
|
|
856
|
+
const node = await this.find(id);
|
|
857
|
+
if (!node) throw new Error(`"${id}" not found.`);
|
|
858
|
+
return node;
|
|
859
|
+
},
|
|
860
|
+
find: (id) => this.find(id),
|
|
861
|
+
resourcex: this.resourcex,
|
|
862
|
+
issuex: this.issuex,
|
|
863
|
+
prototype: this.repo.prototype,
|
|
864
|
+
direct: (locator, args) => this.direct(locator, args)
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
/** Genesis — create the world on first run. Settles built-in prototypes. */
|
|
868
|
+
async genesis() {
|
|
869
|
+
await this.initializer?.bootstrap();
|
|
870
|
+
for (const source of this.bootstrap) {
|
|
871
|
+
await this.direct("!prototype.settle", { source });
|
|
574
872
|
}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
873
|
+
}
|
|
874
|
+
/**
|
|
875
|
+
* Activate a role — returns a stateful Role handle.
|
|
876
|
+
*
|
|
877
|
+
* If the individual does not exist in runtime but a prototype is registered,
|
|
878
|
+
* auto-born the individual first.
|
|
879
|
+
*/
|
|
880
|
+
async activate(individual) {
|
|
881
|
+
let node = await this.find(individual);
|
|
882
|
+
if (!node) {
|
|
883
|
+
const hasProto = Object.hasOwn(this.repo.prototype.list(), individual);
|
|
884
|
+
if (hasProto) {
|
|
885
|
+
await this.ops["individual.born"](void 0, individual);
|
|
886
|
+
node = await this.find(individual);
|
|
887
|
+
} else {
|
|
888
|
+
throw new Error(`"${individual}" not found.`);
|
|
586
889
|
}
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
890
|
+
}
|
|
891
|
+
const state = await this.rt.project(node);
|
|
892
|
+
const ctx = new RoleContext(individual);
|
|
893
|
+
ctx.rehydrate(state);
|
|
894
|
+
const persisted = await this.repo.loadContext(individual);
|
|
895
|
+
if (persisted) {
|
|
896
|
+
if (persisted.focusedGoalId && await this.find(persisted.focusedGoalId)) {
|
|
897
|
+
ctx.focusedGoalId = persisted.focusedGoalId;
|
|
590
898
|
}
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
const mAlias = Array.isArray(m.target.alias) && m.target.alias.length ? ` (${m.target.alias.join(", ")})` : "";
|
|
594
|
-
const mTag = m.target.tags?.length ? ` ${m.target.tags.map((t) => `#${t}`).join(" ")}` : "";
|
|
595
|
-
const posLabels = individualPositions.get(m.target.id ?? "");
|
|
596
|
-
const posStr = posLabels?.length ? ` \u2014 ${posLabels.join(", ")}` : "";
|
|
597
|
-
lines.push(` ${m.target.id}${mAlias}${mTag}${posStr}`);
|
|
899
|
+
if (persisted.focusedPlanId && await this.find(persisted.focusedPlanId)) {
|
|
900
|
+
ctx.focusedPlanId = persisted.focusedPlanId;
|
|
598
901
|
}
|
|
599
|
-
lines.push("");
|
|
600
902
|
}
|
|
601
|
-
const
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
903
|
+
const ops = this.ops;
|
|
904
|
+
const repo = this.repo;
|
|
905
|
+
const saveCtx = async (c) => {
|
|
906
|
+
await repo.saveContext(c.roleId, {
|
|
907
|
+
focusedGoalId: c.focusedGoalId,
|
|
908
|
+
focusedPlanId: c.focusedPlanId
|
|
909
|
+
});
|
|
910
|
+
};
|
|
911
|
+
const api = {
|
|
912
|
+
ops,
|
|
913
|
+
saveCtx,
|
|
914
|
+
direct: this.direct.bind(this),
|
|
915
|
+
resolveLabels: this.issuex ? async (ids) => {
|
|
916
|
+
const names = [];
|
|
917
|
+
for (const id of ids) {
|
|
918
|
+
const label = await this.issuex.getLabel(id);
|
|
919
|
+
if (label) names.push(label.name);
|
|
920
|
+
}
|
|
921
|
+
return names;
|
|
922
|
+
} : void 0
|
|
923
|
+
};
|
|
924
|
+
return new Role(individual, ctx, api);
|
|
925
|
+
}
|
|
926
|
+
/** Find a node by id or alias across the entire society tree. Internal use only. */
|
|
927
|
+
async find(id) {
|
|
928
|
+
const state = await this.rt.project(this.society);
|
|
929
|
+
return findInState(state, id);
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* Direct the world to execute an instruction.
|
|
933
|
+
*
|
|
934
|
+
* - `!namespace.method` — dispatch to ops
|
|
935
|
+
* - anything else — delegate to ResourceX `ingest`
|
|
936
|
+
*/
|
|
937
|
+
async direct(locator, args) {
|
|
938
|
+
if (locator.startsWith("!")) {
|
|
939
|
+
const command = locator.slice(1);
|
|
940
|
+
const fn = this.ops[command];
|
|
941
|
+
if (!fn) {
|
|
942
|
+
const hint2 = directives2["identity-ethics"]?.["on-unknown-command"] ?? "";
|
|
943
|
+
throw new Error(
|
|
944
|
+
`Unknown command "${locator}".
|
|
945
|
+
|
|
946
|
+
You may be guessing the command name. Load the relevant skill first with skill(locator) to learn the correct syntax.
|
|
947
|
+
|
|
948
|
+
` + hint2
|
|
949
|
+
);
|
|
610
950
|
}
|
|
951
|
+
return await fn(...toArgs(command, args ?? {}));
|
|
611
952
|
}
|
|
612
|
-
|
|
953
|
+
if (!this.resourcex) throw new Error("ResourceX is not available.");
|
|
954
|
+
return this.resourcex.ingest(locator, args);
|
|
613
955
|
}
|
|
614
956
|
};
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
function createRendererRouter() {
|
|
618
|
-
return new RendererRouter().register("role", new RoleRenderer()).register("org", new OrgRenderer()).register("position", new PositionRenderer()).register("product", new ProductRenderer()).register("project", new ProjectRenderer()).register("society", new SocietyRenderer()).register("survey", new SurveyRenderer()).register("inspect", new InspectRenderer());
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
// src/rolex.ts
|
|
622
|
-
function createRoleX(config) {
|
|
623
|
-
return createBuilder({
|
|
624
|
-
platform: config.platform,
|
|
625
|
-
renderer: config.renderer ?? createRendererRouter(),
|
|
626
|
-
prototypes: [genesis]
|
|
627
|
-
});
|
|
957
|
+
async function createRoleX(platform) {
|
|
958
|
+
return Rolex.create(platform);
|
|
628
959
|
}
|
|
629
960
|
export {
|
|
961
|
+
Role,
|
|
962
|
+
RoleContext,
|
|
963
|
+
Rolex,
|
|
630
964
|
createRoleX,
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
965
|
+
describe,
|
|
966
|
+
detail,
|
|
967
|
+
directive,
|
|
968
|
+
findInState,
|
|
969
|
+
hint,
|
|
970
|
+
parse,
|
|
971
|
+
render,
|
|
972
|
+
renderComment,
|
|
973
|
+
renderCommentList,
|
|
974
|
+
renderIssue,
|
|
975
|
+
renderIssueList,
|
|
976
|
+
renderIssueResult,
|
|
977
|
+
renderProject,
|
|
978
|
+
renderProjectResult,
|
|
979
|
+
renderState,
|
|
980
|
+
serialize,
|
|
981
|
+
world
|
|
634
982
|
};
|
|
635
983
|
//# sourceMappingURL=index.js.map
|