@positronic/cli 0.0.37 → 0.0.39

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.
@@ -1,32 +1,3 @@
1
- function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
2
- try {
3
- var info = gen[key](arg);
4
- var value = info.value;
5
- } catch (error) {
6
- reject(error);
7
- return;
8
- }
9
- if (info.done) {
10
- resolve(value);
11
- } else {
12
- Promise.resolve(value).then(_next, _throw);
13
- }
14
- }
15
- function _async_to_generator(fn) {
16
- return function() {
17
- var self = this, args = arguments;
18
- return new Promise(function(resolve, reject) {
19
- var gen = fn.apply(self, args);
20
- function _next(value) {
21
- asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
22
- }
23
- function _throw(err) {
24
- asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
25
- }
26
- _next(undefined);
27
- });
28
- };
29
- }
30
1
  function _class_call_check(instance, Constructor) {
31
2
  if (!(instance instanceof Constructor)) {
32
3
  throw new TypeError("Cannot call a class as a function");
@@ -46,134 +17,16 @@ function _create_class(Constructor, protoProps, staticProps) {
46
17
  if (staticProps) _defineProperties(Constructor, staticProps);
47
18
  return Constructor;
48
19
  }
49
- function _define_property(obj, key, value) {
50
- if (key in obj) {
51
- Object.defineProperty(obj, key, {
52
- value: value,
53
- enumerable: true,
54
- configurable: true,
55
- writable: true
56
- });
57
- } else {
58
- obj[key] = value;
59
- }
60
- return obj;
61
- }
62
- function _object_spread(target) {
63
- for(var i = 1; i < arguments.length; i++){
64
- var source = arguments[i] != null ? arguments[i] : {};
65
- var ownKeys = Object.keys(source);
66
- if (typeof Object.getOwnPropertySymbols === "function") {
67
- ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
68
- return Object.getOwnPropertyDescriptor(source, sym).enumerable;
69
- }));
70
- }
71
- ownKeys.forEach(function(key) {
72
- _define_property(target, key, source[key]);
73
- });
74
- }
75
- return target;
76
- }
77
- function _ts_generator(thisArg, body) {
78
- var f, y, t, _ = {
79
- label: 0,
80
- sent: function() {
81
- if (t[0] & 1) throw t[1];
82
- return t[1];
83
- },
84
- trys: [],
85
- ops: []
86
- }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
87
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() {
88
- return this;
89
- }), g;
90
- function verb(n) {
91
- return function(v) {
92
- return step([
93
- n,
94
- v
95
- ]);
96
- };
97
- }
98
- function step(op) {
99
- if (f) throw new TypeError("Generator is already executing.");
100
- while(g && (g = 0, op[0] && (_ = 0)), _)try {
101
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
102
- if (y = 0, t) op = [
103
- op[0] & 2,
104
- t.value
105
- ];
106
- switch(op[0]){
107
- case 0:
108
- case 1:
109
- t = op;
110
- break;
111
- case 4:
112
- _.label++;
113
- return {
114
- value: op[1],
115
- done: false
116
- };
117
- case 5:
118
- _.label++;
119
- y = op[1];
120
- op = [
121
- 0
122
- ];
123
- continue;
124
- case 7:
125
- op = _.ops.pop();
126
- _.trys.pop();
127
- continue;
128
- default:
129
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
130
- _ = 0;
131
- continue;
132
- }
133
- if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
134
- _.label = op[1];
135
- break;
136
- }
137
- if (op[0] === 6 && _.label < t[1]) {
138
- _.label = t[1];
139
- t = op;
140
- break;
141
- }
142
- if (t && _.label < t[2]) {
143
- _.label = t[2];
144
- _.ops.push(op);
145
- break;
146
- }
147
- if (t[2]) _.ops.pop();
148
- _.trys.pop();
149
- continue;
150
- }
151
- op = body.call(thisArg, _);
152
- } catch (e) {
153
- op = [
154
- 6,
155
- e
156
- ];
157
- y = 0;
158
- } finally{
159
- f = t = 0;
160
- }
161
- if (op[0] & 5) throw op[1];
162
- return {
163
- value: op[0] ? op[1] : void 0,
164
- done: true
165
- };
166
- }
167
- }
168
- import { apiClient, isApiLocalDevMode } from './helpers.js';
169
20
  import React from 'react';
170
- import { Text } from 'ink';
171
21
  import { Watch } from '../components/watch.js';
172
22
  import { BrainList } from '../components/brain-list.js';
173
23
  import { BrainHistory } from '../components/brain-history.js';
174
24
  import { RunShow } from '../components/run-show.js';
175
25
  import { BrainRerun } from '../components/brain-rerun.js';
176
26
  import { BrainKill } from '../components/brain-kill.js';
27
+ import { BrainRun } from '../components/brain-run.js';
28
+ import { BrainResolver } from '../components/brain-resolver.js';
29
+ import { BrainWatchWithResolver } from '../components/brain-watch.js';
177
30
  import { ErrorComponent } from '../components/error.js';
178
31
  export var BrainCommand = /*#__PURE__*/ function() {
179
32
  "use strict";
@@ -190,10 +43,15 @@ export var BrainCommand = /*#__PURE__*/ function() {
190
43
  {
191
44
  key: "history",
192
45
  value: function history(param) {
193
- var filename = param.filename, limit = param.limit;
194
- return React.createElement(BrainHistory, {
195
- brainName: filename,
196
- limit: limit
46
+ var brain = param.brain, limit = param.limit;
47
+ return React.createElement(BrainResolver, {
48
+ identifier: brain,
49
+ children: function(resolvedBrainTitle) {
50
+ return React.createElement(BrainHistory, {
51
+ brainName: resolvedBrainTitle,
52
+ limit: limit
53
+ });
54
+ }
197
55
  });
198
56
  }
199
57
  },
@@ -209,272 +67,56 @@ export var BrainCommand = /*#__PURE__*/ function() {
209
67
  {
210
68
  key: "rerun",
211
69
  value: function rerun(param) {
212
- var filename = param.filename, runId = param.runId, startsAt = param.startsAt, stopsAfter = param.stopsAfter;
213
- return React.createElement(BrainRerun, {
214
- identifier: filename,
215
- runId: runId,
216
- startsAt: startsAt,
217
- stopsAfter: stopsAfter
70
+ var brain = param.brain, runId = param.runId, startsAt = param.startsAt, stopsAfter = param.stopsAfter;
71
+ return React.createElement(BrainResolver, {
72
+ identifier: brain,
73
+ children: function(resolvedBrainTitle) {
74
+ return React.createElement(BrainRerun, {
75
+ identifier: resolvedBrainTitle,
76
+ runId: runId,
77
+ startsAt: startsAt,
78
+ stopsAfter: stopsAfter
79
+ });
80
+ }
218
81
  });
219
82
  }
220
83
  },
221
84
  {
222
85
  key: "run",
223
- value: function run(_0) {
224
- return _async_to_generator(function(param) {
225
- var filename, watch, options, apiPath, response, result, errorText, error;
226
- return _ts_generator(this, function(_state) {
227
- switch(_state.label){
228
- case 0:
229
- filename = param.filename, watch = param.watch, options = param.options;
230
- apiPath = '/brains/runs';
231
- _state.label = 1;
232
- case 1:
233
- _state.trys.push([
234
- 1,
235
- 8,
236
- ,
237
- 9
238
- ]);
239
- return [
240
- 4,
241
- apiClient.fetch(apiPath, {
242
- method: 'POST',
243
- headers: {
244
- 'Content-Type': 'application/json'
245
- },
246
- body: JSON.stringify({
247
- identifier: filename,
248
- options: options
249
- })
250
- })
251
- ];
252
- case 2:
253
- response = _state.sent();
254
- if (!(response.status === 201)) return [
255
- 3,
256
- 4
257
- ];
258
- return [
259
- 4,
260
- response.json()
261
- ];
262
- case 3:
263
- result = _state.sent();
264
- if (watch) {
265
- // Return Watch component for CLI to render
266
- return [
267
- 2,
268
- this.watch({
269
- runId: result.brainRunId,
270
- _: [],
271
- $0: ''
272
- })
273
- ];
274
- } else {
275
- // Return React element displaying the run ID
276
- return [
277
- 2,
278
- React.createElement(Text, null, "Run ID: ".concat(result.brainRunId))
279
- ];
280
- }
281
- return [
282
- 3,
283
- 7
284
- ];
285
- case 4:
286
- if (!(response.status === 404)) return [
287
- 3,
288
- 5
289
- ];
290
- // Handle brain not found with a helpful message
291
- return [
292
- 2,
293
- React.createElement(ErrorComponent, {
294
- error: {
295
- title: 'Brain Not Found',
296
- message: "Brain '".concat(filename, "' not found."),
297
- details: 'Please check that:\n 1. The brain name is spelled correctly\n 2. The brain exists in your project\n 3. The brain has been properly defined and exported\n\nYou can list available brains with: positronic list'
298
- }
299
- })
300
- ];
301
- case 5:
302
- return [
303
- 4,
304
- response.text()
305
- ];
306
- case 6:
307
- errorText = _state.sent();
308
- console.error("Error starting brain run: ".concat(response.status, " ").concat(response.statusText));
309
- console.error("Server response: ".concat(errorText));
310
- process.exit(1);
311
- _state.label = 7;
312
- case 7:
313
- return [
314
- 3,
315
- 9
316
- ];
317
- case 8:
318
- error = _state.sent();
319
- if (isApiLocalDevMode()) {
320
- console.error("Error connecting to the local development server.");
321
- console.error("Please ensure the server is running ('positronic server' or 'px s').");
322
- } else {
323
- console.error("Error connecting to the remote project server.");
324
- console.error('Please check your network connection and verify the project URL is correct.');
325
- }
326
- if (error.code === 'ECONNREFUSED') {
327
- console.error('Reason: Connection refused. The server might not be running or is listening on a different port.');
328
- } else {
329
- console.error("Fetch error details: ".concat(error.message));
330
- }
331
- process.exit(1);
332
- return [
333
- 3,
334
- 9
335
- ];
336
- case 9:
337
- return [
338
- 2
339
- ];
340
- }
341
- });
342
- }).apply(this, arguments);
86
+ value: function run(param) {
87
+ var brain = param.brain, watch = param.watch, options = param.options;
88
+ return React.createElement(BrainRun, {
89
+ identifier: brain,
90
+ watch: watch,
91
+ options: options
92
+ });
343
93
  }
344
94
  },
345
95
  {
346
96
  key: "watch",
347
- value: function watch(_0) {
348
- return _async_to_generator(function(param) {
349
- var runId, filename, apiPath, response, result, activeRun, errorText, error, connectionError;
350
- return _ts_generator(this, function(_state) {
351
- switch(_state.label){
352
- case 0:
353
- runId = param.runId, filename = param.filename;
354
- // If a specific run ID is provided, return the Watch component
355
- if (runId) {
356
- return [
357
- 2,
358
- React.createElement(Watch, {
359
- runId: runId
360
- })
361
- ];
362
- }
363
- if (!filename) return [
364
- 3,
365
- 8
366
- ];
367
- _state.label = 1;
368
- case 1:
369
- _state.trys.push([
370
- 1,
371
- 7,
372
- ,
373
- 8
374
- ]);
375
- apiPath = "/brains/".concat(encodeURIComponent(filename), "/active-runs");
376
- return [
377
- 4,
378
- apiClient.fetch(apiPath, {
379
- method: 'GET'
380
- })
381
- ];
382
- case 2:
383
- response = _state.sent();
384
- if (!(response.status === 200)) return [
385
- 3,
386
- 4
387
- ];
388
- return [
389
- 4,
390
- response.json()
391
- ];
392
- case 3:
393
- result = _state.sent();
394
- if (result.runs.length === 0) {
395
- return [
396
- 2,
397
- React.createElement(ErrorComponent, {
398
- error: {
399
- title: 'No Active Runs',
400
- message: 'No currently running brain runs found for brain "'.concat(filename, '".'),
401
- details: "To start a new run, use: positronic run ".concat(filename)
402
- }
403
- })
404
- ];
405
- }
406
- if (result.runs.length > 1) {
407
- return [
408
- 2,
409
- React.createElement(ErrorComponent, {
410
- error: {
411
- title: 'Multiple Active Runs',
412
- message: "Found ".concat(result.runs.length, ' active runs for brain "').concat(filename, '".'),
413
- details: "Please specify a specific run ID with --run-id:\n".concat(result.runs.map(function(run) {
414
- return " positronic watch --run-id ".concat(run.brainRunId);
415
- }).join('\n'))
416
- }
417
- })
418
- ];
419
- }
420
- // Exactly one active run found - watch it
421
- activeRun = result.runs[0];
422
- return [
423
- 2,
424
- React.createElement(Watch, {
425
- runId: activeRun.brainRunId
426
- })
427
- ];
428
- case 4:
429
- return [
430
- 4,
431
- response.text()
432
- ];
433
- case 5:
434
- errorText = _state.sent();
435
- return [
436
- 2,
437
- React.createElement(ErrorComponent, {
438
- error: {
439
- title: 'API Error',
440
- message: 'Failed to get active runs for brain "'.concat(filename, '".'),
441
- details: "Server returned ".concat(response.status, ": ").concat(errorText)
442
- }
443
- })
444
- ];
445
- case 6:
446
- return [
447
- 3,
448
- 8
449
- ];
450
- case 7:
451
- error = _state.sent();
452
- connectionError = isApiLocalDevMode() ? {
453
- message: 'Error connecting to the local development server.',
454
- details: "Please ensure the server is running ('positronic server' or 'px s').\n\nError details: ".concat(error.message)
455
- } : {
456
- message: 'Error connecting to the remote project server.',
457
- details: "Please check your network connection and verify the project URL is correct.\n\nError details: ".concat(error.message)
458
- };
459
- return [
460
- 2,
461
- React.createElement(ErrorComponent, {
462
- error: _object_spread({
463
- title: 'Connection Error'
464
- }, connectionError)
465
- })
466
- ];
467
- case 8:
468
- // Neither runId nor brainName provided – return an error element.
469
- return [
470
- 2,
471
- React.createElement(Text, {
472
- color: 'red'
473
- }, 'Error: You must provide either a brain run ID or a brain name.')
474
- ];
475
- }
97
+ value: function watch(param) {
98
+ var runId = param.runId, brain = param.brain;
99
+ // If a specific run ID is provided, return the Watch component
100
+ if (runId) {
101
+ return React.createElement(Watch, {
102
+ runId: runId
476
103
  });
477
- }).apply(this, arguments);
104
+ }
105
+ // If watching by brain identifier is requested, use BrainWatchWithResolver
106
+ // which handles fuzzy search, disambiguation, and active run lookup
107
+ if (brain) {
108
+ return React.createElement(BrainWatchWithResolver, {
109
+ identifier: brain
110
+ });
111
+ }
112
+ // Neither runId nor brainName provided – return an error element.
113
+ return React.createElement(ErrorComponent, {
114
+ error: {
115
+ title: 'Missing Argument',
116
+ message: 'You must provide either a brain run ID or a brain identifier.',
117
+ details: 'Use --run-id to watch a specific run, or --brain to watch the active run of a brain.'
118
+ }
119
+ });
478
120
  }
479
121
  },
480
122
  {
@@ -22,6 +22,7 @@ import { ScheduleCreate } from '../components/schedule-create.js';
22
22
  import { ScheduleList } from '../components/schedule-list.js';
23
23
  import { ScheduleDelete } from '../components/schedule-delete.js';
24
24
  import { ScheduleRuns } from '../components/schedule-runs.js';
25
+ import { BrainResolver } from '../components/brain-resolver.js';
25
26
  export var ScheduleCommand = /*#__PURE__*/ function() {
26
27
  "use strict";
27
28
  function ScheduleCommand() {
@@ -31,10 +32,15 @@ export var ScheduleCommand = /*#__PURE__*/ function() {
31
32
  {
32
33
  key: "create",
33
34
  value: function create(param) {
34
- var brainFilename = param.brainFilename, cronExpression = param.cronExpression;
35
- return React.createElement(ScheduleCreate, {
36
- identifier: brainFilename,
37
- cronExpression: cronExpression
35
+ var brain = param.brain, cronExpression = param.cronExpression;
36
+ return React.createElement(BrainResolver, {
37
+ identifier: brain,
38
+ children: function(resolvedBrainTitle) {
39
+ return React.createElement(ScheduleCreate, {
40
+ identifier: resolvedBrainTitle,
41
+ cronExpression: cronExpression
42
+ });
43
+ }
38
44
  });
39
45
  }
40
46
  },
@@ -27,15 +27,49 @@ import React from 'react';
27
27
  import { Text, Box } from 'ink';
28
28
  import { ErrorComponent } from './error.js';
29
29
  import { useApiGet } from '../hooks/useApi.js';
30
- // Helper to truncate text to fit column width
31
- var truncate = function(text, maxWidth) {
32
- if (text.length <= maxWidth) return text;
33
- return text.substring(0, maxWidth - 3) + '...';
34
- };
35
30
  // Helper to pad text to column width
36
31
  var padRight = function(text, width) {
37
32
  return text + ' '.repeat(Math.max(0, width - text.length));
38
33
  };
34
+ // Helper to wrap text to multiple lines
35
+ var wrapText = function(text, maxWidth) {
36
+ var words = text.split(' ');
37
+ var lines = [];
38
+ var currentLine = '';
39
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
40
+ try {
41
+ for(var _iterator = words[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
42
+ var word = _step.value;
43
+ if (currentLine.length === 0) {
44
+ currentLine = word;
45
+ } else if (currentLine.length + 1 + word.length <= maxWidth) {
46
+ currentLine += ' ' + word;
47
+ } else {
48
+ lines.push(currentLine);
49
+ currentLine = word;
50
+ }
51
+ }
52
+ } catch (err) {
53
+ _didIteratorError = true;
54
+ _iteratorError = err;
55
+ } finally{
56
+ try {
57
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
58
+ _iterator.return();
59
+ }
60
+ } finally{
61
+ if (_didIteratorError) {
62
+ throw _iteratorError;
63
+ }
64
+ }
65
+ }
66
+ if (currentLine.length > 0) {
67
+ lines.push(currentLine);
68
+ }
69
+ return lines.length > 0 ? lines : [
70
+ ''
71
+ ];
72
+ };
39
73
  export var BrainList = function() {
40
74
  var _useApiGet = useApiGet('/brains'), data = _useApiGet.data, loading = _useApiGet.loading, error = _useApiGet.error;
41
75
  if (error) {
@@ -55,23 +89,19 @@ export var BrainList = function() {
55
89
  dimColor: true
56
90
  }, 'Tip: Create a brain with "px brain new <name>" or add .ts files to the brains/ directory')));
57
91
  }
58
- // Sort brains alphabetically by filename
92
+ // Sort brains alphabetically by title
59
93
  var sortedBrains = _to_consumable_array(data.brains).sort(function(a, b) {
60
- return a.filename.localeCompare(b.filename);
94
+ return a.title.localeCompare(b.title);
61
95
  });
62
96
  // Define column widths
63
97
  var columns = {
64
- filename: {
65
- header: 'Filename',
66
- width: 25
67
- },
68
98
  title: {
69
- header: 'Title',
70
- width: 35
99
+ header: 'Brain',
100
+ width: 25
71
101
  },
72
102
  description: {
73
103
  header: 'Description',
74
- width: 50
104
+ width: 70
75
105
  }
76
106
  };
77
107
  // Calculate total width for separator
@@ -90,19 +120,25 @@ export var BrainList = function() {
90
120
  }, /*#__PURE__*/ React.createElement(Box, null, /*#__PURE__*/ React.createElement(Text, {
91
121
  bold: true,
92
122
  color: "cyan"
93
- }, padRight(columns.filename.header, columns.filename.width)), /*#__PURE__*/ React.createElement(Text, null, " "), /*#__PURE__*/ React.createElement(Text, {
94
- bold: true,
95
- color: "cyan"
96
123
  }, padRight(columns.title.header, columns.title.width)), /*#__PURE__*/ React.createElement(Text, null, " "), /*#__PURE__*/ React.createElement(Text, {
97
124
  bold: true,
98
125
  color: "cyan"
99
- }, padRight(columns.description.header, columns.description.width))), /*#__PURE__*/ React.createElement(Box, null, /*#__PURE__*/ React.createElement(Text, {
126
+ }, columns.description.header)), /*#__PURE__*/ React.createElement(Box, null, /*#__PURE__*/ React.createElement(Text, {
100
127
  dimColor: true
101
128
  }, '─'.repeat(totalWidth))), sortedBrains.map(function(brain) {
129
+ var descriptionLines = wrapText(brain.description, columns.description.width);
102
130
  return /*#__PURE__*/ React.createElement(Box, {
103
- key: brain.filename
104
- }, /*#__PURE__*/ React.createElement(Text, null, padRight(truncate(brain.filename, columns.filename.width), columns.filename.width)), /*#__PURE__*/ React.createElement(Text, null, " "), /*#__PURE__*/ React.createElement(Text, null, padRight(truncate(brain.title, columns.title.width), columns.title.width)), /*#__PURE__*/ React.createElement(Text, null, " "), /*#__PURE__*/ React.createElement(Text, {
131
+ key: brain.filename,
132
+ flexDirection: "column",
133
+ marginBottom: descriptionLines.length > 1 ? 1 : 0
134
+ }, /*#__PURE__*/ React.createElement(Box, null, /*#__PURE__*/ React.createElement(Text, null, padRight(brain.title.length > columns.title.width ? brain.title.substring(0, columns.title.width - 3) + '...' : brain.title, columns.title.width)), /*#__PURE__*/ React.createElement(Text, null, " "), /*#__PURE__*/ React.createElement(Text, {
105
135
  dimColor: true
106
- }, padRight(truncate(brain.description, columns.description.width), columns.description.width)));
136
+ }, descriptionLines[0])), descriptionLines.slice(1).map(function(line, index) {
137
+ return /*#__PURE__*/ React.createElement(Box, {
138
+ key: index
139
+ }, /*#__PURE__*/ React.createElement(Text, null, ' '.repeat(columns.title.width)), /*#__PURE__*/ React.createElement(Text, null, " "), /*#__PURE__*/ React.createElement(Text, {
140
+ dimColor: true
141
+ }, line));
142
+ }));
107
143
  })));
108
144
  };