trucontext 0.3.0 → 0.3.1
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/bin/cli.js +9 -3
- package/package.json +1 -1
- package/src/commands/entities.js +91 -16
package/bin/cli.js
CHANGED
|
@@ -11,14 +11,14 @@ import { queryCommand } from '../src/commands/query.js';
|
|
|
11
11
|
import { recallCommand } from '../src/commands/recall.js';
|
|
12
12
|
import { contextsListCommand, contextsCreateCommand, contextsDeleteCommand } from '../src/commands/contexts.js';
|
|
13
13
|
import { schemaShowCommand, schemaGenerateCommand, schemaSetAuthorshipCommand } from '../src/commands/schema.js';
|
|
14
|
-
import { entitiesListCommand, entitiesGetCommand, entitiesCreateCommand, entitiesUpdateCommand, entitiesDeleteCommand } from '../src/commands/entities.js';
|
|
14
|
+
import { entitiesListCommand, entitiesGetCommand, entitiesCreateCommand, entitiesUpdateCommand, entitiesDeleteCommand, entitiesEdgesCommand } from '../src/commands/entities.js';
|
|
15
15
|
import { recipesListCommand, recipesGetCommand, recipesCreateCommand, recipesDeleteCommand } from '../src/commands/recipes.js';
|
|
16
16
|
import { relationshipTypesListCommand } from '../src/commands/relationship-types.js';
|
|
17
17
|
|
|
18
18
|
program
|
|
19
19
|
.name('trucontext')
|
|
20
20
|
.description('TruContext CLI — contextual memory for AI applications')
|
|
21
|
-
.version('0.
|
|
21
|
+
.version('0.3.1');
|
|
22
22
|
|
|
23
23
|
// Auth
|
|
24
24
|
program.command('login')
|
|
@@ -88,7 +88,9 @@ const entities = program.command('entities').description('Manage entities').acti
|
|
|
88
88
|
entities.command('list')
|
|
89
89
|
.description('List entities')
|
|
90
90
|
.option('--type <type>', 'Filter by entity type')
|
|
91
|
-
.option('
|
|
91
|
+
.option('--context <id>', 'Filter by context')
|
|
92
|
+
.option('--scope <scope>', 'Filter by scope')
|
|
93
|
+
.option('-l, --limit <n>', 'Max results (default: 50)')
|
|
92
94
|
.action(entitiesListCommand);
|
|
93
95
|
entities.command('get <entityId>')
|
|
94
96
|
.description('Get an entity')
|
|
@@ -114,10 +116,14 @@ entities.command('update <entityId>')
|
|
|
114
116
|
.option('--confidence <n>', 'Confidence level (0.0-1.0)')
|
|
115
117
|
.option('--temporal', 'Content can decay over time')
|
|
116
118
|
.option('--no-temporal', 'Content is a permanent fact')
|
|
119
|
+
.option('-c, --context <entry>', 'Link to context (entity-id:RELATIONSHIP, repeatable)', (val, prev) => [...prev, val], [])
|
|
117
120
|
.action(entitiesUpdateCommand);
|
|
118
121
|
entities.command('delete <entityId>')
|
|
119
122
|
.description('Delete an entity')
|
|
120
123
|
.action(entitiesDeleteCommand);
|
|
124
|
+
entities.command('edges <entityId>')
|
|
125
|
+
.description('List edges for an entity')
|
|
126
|
+
.action(entitiesEdgesCommand);
|
|
121
127
|
|
|
122
128
|
// Recipes
|
|
123
129
|
const recipes = program.command('recipes').description('Manage recipes').action(function() { this.help(); });
|
package/package.json
CHANGED
package/src/commands/entities.js
CHANGED
|
@@ -1,10 +1,47 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { dataPlane } from '../client.js';
|
|
3
3
|
|
|
4
|
+
// Fields stored on the node but not user-declared properties
|
|
5
|
+
const SYSTEM_FIELDS = new Set([
|
|
6
|
+
'tenantId', 'entityId', 'provenance', 'scope', 'createdAt', 'updatedAt',
|
|
7
|
+
'lastReinforcedAt', 'confidence', 'temporal', 'heartbeat_enabled', 'recipe_id',
|
|
8
|
+
]);
|
|
9
|
+
|
|
10
|
+
function displayEntity(e) {
|
|
11
|
+
const props = e.properties || {};
|
|
12
|
+
const type = e.type || e.labels?.[0] || 'Unknown';
|
|
13
|
+
const entityId = e.entityId || props.entityId;
|
|
14
|
+
const confidence = e.confidence ?? props.confidence;
|
|
15
|
+
const temporal = e.temporal ?? props.temporal;
|
|
16
|
+
const recipeId = e.recipe_id ?? props.recipe_id;
|
|
17
|
+
const heartbeat = e.heartbeat_enabled ?? props.heartbeat_enabled;
|
|
18
|
+
const provenance = e.provenance ?? props.provenance;
|
|
19
|
+
|
|
20
|
+
console.log(`${chalk.bold(entityId)} ${chalk.dim(`[${type}]`)}`);
|
|
21
|
+
if (provenance) console.log(` provenance: ${chalk.dim(provenance)}`);
|
|
22
|
+
if (recipeId) console.log(` recipe: ${chalk.cyan(recipeId)}`);
|
|
23
|
+
if (confidence !== undefined) console.log(` confidence: ${chalk.dim(confidence)}`);
|
|
24
|
+
if (temporal !== undefined) console.log(` temporal: ${chalk.dim(temporal)}`);
|
|
25
|
+
if (heartbeat !== undefined) console.log(` heartbeat: ${chalk.dim(heartbeat)}`);
|
|
26
|
+
|
|
27
|
+
// Show user-declared properties (exclude system fields)
|
|
28
|
+
const userProps = {};
|
|
29
|
+
for (const [k, v] of Object.entries(props)) {
|
|
30
|
+
if (!SYSTEM_FIELDS.has(k) && v !== null && v !== undefined) {
|
|
31
|
+
userProps[k] = v;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (Object.keys(userProps).length > 0) {
|
|
35
|
+
console.log(` properties: ${chalk.dim(JSON.stringify(userProps))}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
4
39
|
export async function entitiesListCommand(options) {
|
|
5
40
|
try {
|
|
6
41
|
const params = new URLSearchParams();
|
|
7
42
|
if (options.type) params.set('type', options.type);
|
|
43
|
+
if (options.context) params.set('context_id', options.context);
|
|
44
|
+
if (options.scope) params.set('scope', options.scope);
|
|
8
45
|
if (options.limit) params.set('limit', options.limit);
|
|
9
46
|
const qs = params.toString();
|
|
10
47
|
const path = `/v1/entities${qs ? `?${qs}` : ''}`;
|
|
@@ -18,15 +55,9 @@ export async function entitiesListCommand(options) {
|
|
|
18
55
|
}
|
|
19
56
|
|
|
20
57
|
for (const e of entities) {
|
|
21
|
-
|
|
22
|
-
if (e.recipe_id) console.log(` recipe: ${chalk.dim(e.recipe_id)}`);
|
|
23
|
-
if (e.properties && Object.keys(e.properties).length > 0) {
|
|
24
|
-
console.log(` properties: ${chalk.dim(JSON.stringify(e.properties))}`);
|
|
25
|
-
}
|
|
26
|
-
if (e.heartbeat_enabled !== undefined) console.log(` heartbeat: ${chalk.dim(e.heartbeat_enabled)}`);
|
|
27
|
-
if (e.confidence !== undefined) console.log(` confidence: ${chalk.dim(e.confidence)}`);
|
|
28
|
-
if (e.temporal !== undefined) console.log(` temporal: ${chalk.dim(e.temporal)}`);
|
|
58
|
+
displayEntity(e);
|
|
29
59
|
}
|
|
60
|
+
console.log(chalk.dim(`\n${entities.length} entities`));
|
|
30
61
|
} catch (err) {
|
|
31
62
|
console.error(chalk.red(`Failed: ${err.message}`));
|
|
32
63
|
process.exit(1);
|
|
@@ -37,15 +68,22 @@ export async function entitiesGetCommand(entityId) {
|
|
|
37
68
|
try {
|
|
38
69
|
const res = await dataPlane('GET', `/v1/entities/${entityId}`);
|
|
39
70
|
const e = res.data || res;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
71
|
+
displayEntity(e);
|
|
72
|
+
|
|
73
|
+
// Show edges if available
|
|
74
|
+
try {
|
|
75
|
+
const edgeRes = await dataPlane('GET', `/v1/entities/${entityId}/edges`);
|
|
76
|
+
const edges = edgeRes.data?.edges || edgeRes.data || [];
|
|
77
|
+
if (edges.length > 0) {
|
|
78
|
+
console.log(chalk.dim(`\n Edges (${edges.length}):`));
|
|
79
|
+
for (const edge of edges) {
|
|
80
|
+
const dir = edge.direction === 'outgoing' ? '→' : '←';
|
|
81
|
+
console.log(` ${dir} ${chalk.cyan(edge.type)} ${chalk.dim(edge.targetEntityId || edge.targetLabel || edge.target || '')}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
} catch {
|
|
85
|
+
// Edge listing may not be available — skip silently
|
|
45
86
|
}
|
|
46
|
-
if (e.heartbeat_enabled !== undefined) console.log(` heartbeat: ${chalk.dim(e.heartbeat_enabled)}`);
|
|
47
|
-
if (e.confidence !== undefined) console.log(` confidence: ${chalk.dim(e.confidence)}`);
|
|
48
|
-
if (e.temporal !== undefined) console.log(` temporal: ${chalk.dim(e.temporal)}`);
|
|
49
87
|
} catch (err) {
|
|
50
88
|
console.error(chalk.red(`Failed: ${err.message}`));
|
|
51
89
|
process.exit(1);
|
|
@@ -122,6 +160,19 @@ export async function entitiesUpdateCommand(entityId, options) {
|
|
|
122
160
|
if (options.confidence !== undefined) body.confidence = parseFloat(options.confidence);
|
|
123
161
|
if (options.temporal !== undefined) body.temporal = options.temporal;
|
|
124
162
|
|
|
163
|
+
if (options.context?.length > 0) {
|
|
164
|
+
body.contexts = options.context.map(entry => {
|
|
165
|
+
const colonIdx = entry.indexOf(':');
|
|
166
|
+
if (colonIdx === -1) {
|
|
167
|
+
return { context_id: entry, relationship: 'ABOUT' };
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
context_id: entry.slice(0, colonIdx),
|
|
171
|
+
relationship: entry.slice(colonIdx + 1),
|
|
172
|
+
};
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
125
176
|
await dataPlane('PUT', `/v1/entities/${entityId}`, body);
|
|
126
177
|
console.log(chalk.green(`Updated: ${entityId}`));
|
|
127
178
|
} catch (err) {
|
|
@@ -139,3 +190,27 @@ export async function entitiesDeleteCommand(entityId) {
|
|
|
139
190
|
process.exit(1);
|
|
140
191
|
}
|
|
141
192
|
}
|
|
193
|
+
|
|
194
|
+
export async function entitiesEdgesCommand(entityId) {
|
|
195
|
+
try {
|
|
196
|
+
const res = await dataPlane('GET', `/v1/entities/${entityId}/edges`);
|
|
197
|
+
const edges = res.data?.edges || res.data || [];
|
|
198
|
+
|
|
199
|
+
if (edges.length === 0) {
|
|
200
|
+
console.log(chalk.yellow('No edges found.'));
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
for (const edge of edges) {
|
|
205
|
+
const dir = edge.direction === 'outgoing' ? '→' : '←';
|
|
206
|
+
console.log(` ${dir} ${chalk.cyan(edge.type)} ${chalk.dim(edge.targetEntityId || edge.targetLabel || '')}`);
|
|
207
|
+
if (edge.properties && Object.keys(edge.properties).length > 0) {
|
|
208
|
+
console.log(` ${chalk.dim(JSON.stringify(edge.properties))}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
console.log(chalk.dim(`\n${edges.length} edges`));
|
|
212
|
+
} catch (err) {
|
|
213
|
+
console.error(chalk.red(`Failed: ${err.message}`));
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
216
|
+
}
|