trucontext 0.4.1 → 0.5.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 CHANGED
@@ -139,10 +139,11 @@ recipes.command('get <recipeId>')
139
139
  .description('Get recipe details')
140
140
  .action(recipesGetCommand);
141
141
  recipes.command('create')
142
- .description('Create a recipe')
143
- .requiredOption('--id <recipeId>', 'Recipe ID')
144
- .requiredOption('--name <name>', 'Recipe name')
145
- .requiredOption('--purpose <text>', 'Recipe purpose')
142
+ .description('Create a custom recipe. --id and --name are always required. Provide the interpretation via --file (JSON) or inline flags.')
143
+ .requiredOption('--id <recipeId>', 'Recipe ID (e.g., my-health-score)')
144
+ .requiredOption('--name <name>', 'Recipe display name')
145
+ .option('--file <path>', 'JSON file containing the interpretation block (the WHY)')
146
+ .option('--purpose <text>', 'Recipe purpose (inline alternative to --file)')
146
147
  .option('--decay-profile <text>', 'Decay profile description')
147
148
  .option('--confidence-bias <text>', 'Confidence bias description')
148
149
  .action(recipesCreateCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trucontext",
3
- "version": "0.4.1",
3
+ "version": "0.5.1",
4
4
  "description": "TruContext CLI — contextual memory for AI applications",
5
5
  "type": "module",
6
6
  "bin": {
package/src/client.js CHANGED
@@ -1,20 +1,16 @@
1
1
  // client.js — HTTP client for both API planes
2
- // Auto-refreshes JWT, attaches active app header.
2
+ // Auto-refreshes JWT, auto-prefixes appId in data plane paths.
3
3
 
4
4
  import { ensureFreshToken } from './auth.js';
5
5
  import { getActiveApp, DATA_PLANE_URL, CONTROL_PLANE_URL } from './config.js';
6
6
 
7
7
  async function request(baseUrl, method, path, body, retry = true) {
8
8
  const token = await ensureFreshToken();
9
- const activeApp = getActiveApp();
10
9
 
11
10
  const headers = {
12
11
  'Authorization': `Bearer ${token}`,
13
12
  'Content-Type': 'application/json',
14
13
  };
15
- if (activeApp) {
16
- headers['X-TruContext-App'] = activeApp;
17
- }
18
14
 
19
15
  const ac = new AbortController();
20
16
  const timeout = setTimeout(() => ac.abort(), 15000);
@@ -69,7 +65,13 @@ async function handleResponse(res) {
69
65
  // --- Public API ---
70
66
 
71
67
  export function dataPlane(method, path, body) {
72
- return request(DATA_PLANE_URL, method, path, body);
68
+ const appId = getActiveApp();
69
+ if (!appId) {
70
+ throw new Error('No active app. Run: trucontext use <app-id>');
71
+ }
72
+ // Auto-prefix: /v1/entities → /v1/apps/{appId}/entities
73
+ const appPath = path.replace(/^\/v1\//, `/v1/apps/${appId}/`);
74
+ return request(DATA_PLANE_URL, method, appPath, body);
73
75
  }
74
76
 
75
77
  export function controlPlane(method, path, body) {
@@ -1,3 +1,4 @@
1
+ import { readFileSync } from 'fs';
1
2
  import chalk from 'chalk';
2
3
  import { controlPlane } from '../client.js';
3
4
  import { getActiveApp } from '../config.js';
@@ -107,19 +108,35 @@ export async function recipesCreateCommand(options) {
107
108
  console.error(chalk.red('--name is required'));
108
109
  process.exit(1);
109
110
  }
110
- if (!options.purpose) {
111
- console.error(chalk.red('--purpose is required'));
112
- process.exit(1);
113
- }
114
111
 
115
112
  const body = {
116
113
  recipeId: options.id,
117
114
  name: options.name,
118
- purpose: options.purpose,
119
115
  };
120
116
 
121
- if (options.decayProfile) body.decay_profile = options.decayProfile;
122
- if (options.confidenceBias) body.confidence_bias = options.confidenceBias;
117
+ // --file provides the full interpretation block as JSON
118
+ if (options.file) {
119
+ try {
120
+ const raw = readFileSync(options.file, 'utf8');
121
+ body.interpretation = JSON.parse(raw);
122
+ if (!body.interpretation.purpose) {
123
+ console.error(chalk.red('File must contain a "purpose" field'));
124
+ process.exit(1);
125
+ }
126
+ } catch (e) {
127
+ console.error(chalk.red(`Failed to read --file: ${e.message}`));
128
+ process.exit(1);
129
+ }
130
+ } else {
131
+ // Inline flags → build interpretation object
132
+ if (!options.purpose) {
133
+ console.error(chalk.red('--purpose is required (or use --file to provide the full interpretation)'));
134
+ process.exit(1);
135
+ }
136
+ body.interpretation = { purpose: options.purpose };
137
+ if (options.decayProfile) body.interpretation.decay_profile = options.decayProfile;
138
+ if (options.confidenceBias) body.interpretation.confidence_bias = options.confidenceBias;
139
+ }
123
140
 
124
141
  const res = await controlPlane('POST', `/apps/${appId}/recipes`, body);
125
142
  const r = res.data || res;