@owlmeans/viable-sdk 0.1.18-rc.21 → 0.1.18-rc.22
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 +1 -1
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/viable-sdk/SKILL.md +15 -15
- package/build/api/remote.d.ts +2 -3
- package/build/api/remote.d.ts.map +1 -1
- package/build/api/remote.js +6 -14
- package/build/api/remote.js.map +1 -1
- package/build/consts.d.ts +3 -13
- package/build/consts.d.ts.map +1 -1
- package/build/consts.js +3 -13
- package/build/consts.js.map +1 -1
- package/build/harness/templates.d.ts +2 -2
- package/build/harness/templates.d.ts.map +1 -1
- package/build/harness/templates.js +10 -10
- package/build/project/setup.d.ts +1 -1
- package/build/tools/catalogue.d.ts +2 -2
- package/build/tools/catalogue.d.ts.map +1 -1
- package/build/tools/catalogue.js +73 -133
- package/build/tools/catalogue.js.map +1 -1
- package/build/tools/index.d.ts +1 -1
- package/build/tools/index.d.ts.map +1 -1
- package/build/tools/index.js +1 -1
- package/build/tools/index.js.map +1 -1
- package/build/tools/mcp.d.ts +2 -2
- package/build/tools/mcp.js +10 -10
- package/build/tools/mcp.js.map +1 -1
- package/build/tools/platform.d.ts +4 -8
- package/build/tools/platform.d.ts.map +1 -1
- package/build/tools/platform.js +22 -36
- package/build/tools/platform.js.map +1 -1
- package/build/tools/refusal.d.ts +2 -2
- package/build/tools/refusal.js +6 -6
- package/build/tools/refusal.js.map +1 -1
- package/build/tools/status.d.ts +6 -0
- package/build/tools/status.d.ts.map +1 -0
- package/build/tools/status.js +102 -0
- package/build/tools/status.js.map +1 -0
- package/build/types.d.ts +16 -17
- package/build/types.d.ts.map +1 -1
- package/package.json +19 -19
- package/build/tools/jobs.d.ts +0 -12
- package/build/tools/jobs.d.ts.map +0 -1
- package/build/tools/jobs.js +0 -60
- package/build/tools/jobs.js.map +0 -1
package/build/tools/catalogue.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { CommitTimeout, TransitionAction, WorkcardKind } from '@owlmeans/planning';
|
|
3
|
-
import {
|
|
4
|
-
import { COMMIT_WAIT_MS,
|
|
3
|
+
import { ConnectTarget, ConversionDecision, ConversionStatus, ConvertibilityVerdict, MODEL_TIER_ROLES, OriginKind, STORY_BAND_MAX_USD, STORY_BAND_MIN_USD, VIABLE_STORY_TYPE, ViableStoryTransition } from '@owlmeans/viable-common';
|
|
4
|
+
import { COMMIT_WAIT_MS, NEXT_QUESTION_WAIT_MS, NEXT_TASK_WAIT_MS, STORY_PAGE_SIZE } from '../consts.js';
|
|
5
5
|
import { describeHarness, installHarness } from '../harness/index.js';
|
|
6
6
|
import { envStatus } from '../project/env.js';
|
|
7
7
|
import { missingServices, readSetupReport, renderSetupGuide, setUserEnv } from '../project/setup.js';
|
|
8
8
|
import { localStatus, runLocal, stopLocal } from '../run/index.js';
|
|
9
9
|
import { parseTaskResult, renderTaskEnvelope } from '../task/envelope.js';
|
|
10
10
|
import { parseAnswer, renderQuestionEnvelope } from '../task/inquiry.js';
|
|
11
|
-
import { renderJob } from './jobs.js';
|
|
12
11
|
import { PLATFORM_CATALOGUE, renderPlatform } from './platform.js';
|
|
13
12
|
import { refusalMessage, refusalPhrase } from './refusal.js';
|
|
13
|
+
import { conversionNext, renderPipelineStatus, renderProjectStatus, renderStoryStatus, } from './status.js';
|
|
14
14
|
import { renderStories, resolveStory, STORY_ORDER, storyQuery } from './stories.js';
|
|
15
15
|
import { anyHost, cloudTarget, localTarget, performsModelTasks, sessionCapable, ToolHostKind, withExecutor } from './types.js';
|
|
16
16
|
const ok = (text, structured) => ({ text, structured });
|
|
@@ -72,7 +72,10 @@ const projectOf = (args, deps) => {
|
|
|
72
72
|
}
|
|
73
73
|
return project;
|
|
74
74
|
};
|
|
75
|
-
const
|
|
75
|
+
const projectResult = (status) => ok(renderProjectStatus(status), { project: status });
|
|
76
|
+
const storyResult = (status) => ok(renderStoryStatus(status), { story: status });
|
|
77
|
+
const pipelineResult = (status) => ok(renderPipelineStatus(status), { pipeline: status });
|
|
78
|
+
const conversionResult = (status) => ok(renderConversion(status), { conversion: status });
|
|
76
79
|
/**
|
|
77
80
|
* Attach a connector, where this host can hold one.
|
|
78
81
|
*
|
|
@@ -123,36 +126,35 @@ const waitForStoryCleanup = async (deps, projectId) => {
|
|
|
123
126
|
/** The project a tool acts on when it can also work without one. */
|
|
124
127
|
const projectOrNull = (args, deps) => typeof args.projectId === 'string' ? args.projectId : deps.attached();
|
|
125
128
|
/**
|
|
126
|
-
* The question a
|
|
129
|
+
* The question a parked domain operation is waiting on, when this session holds none.
|
|
127
130
|
*
|
|
128
131
|
* A question is delivered as an operation and answered against it, and that is the fast path. But
|
|
129
132
|
* an operation expires: a run that asked while nobody was attached, or while this connector was
|
|
130
133
|
* being restarted, is left `Waiting` with a question no queue here has ever seen. Without this the
|
|
131
|
-
* only way back to it is the web application, and a parent
|
|
132
|
-
* whole
|
|
134
|
+
* only way back to it is the web application, and a parent watching only the run would wait out the
|
|
135
|
+
* whole interaction on a question it could have carried in seconds.
|
|
133
136
|
*
|
|
134
137
|
* Best-effort on both reads. A project with no conversion answers an error, and failing the call
|
|
135
138
|
* that asked for a question because the lookup for it failed would be worse than answering "none".
|
|
136
139
|
*/
|
|
137
|
-
const parkedQuestion = async (deps, projectId
|
|
140
|
+
const parkedQuestion = async (deps, projectId) => {
|
|
138
141
|
try {
|
|
139
|
-
const status = await deps.api.
|
|
142
|
+
const status = await deps.api.project.status(projectId);
|
|
140
143
|
if (status.pendingInquiry != null)
|
|
141
144
|
return status.pendingInquiry;
|
|
142
145
|
}
|
|
143
146
|
catch (e) {
|
|
144
|
-
deps.log(`no
|
|
147
|
+
deps.log(`no project question for ${projectId}: ${e.message}`);
|
|
145
148
|
}
|
|
146
|
-
if (jobId == null)
|
|
147
|
-
return null;
|
|
148
149
|
try {
|
|
149
|
-
const
|
|
150
|
-
|
|
150
|
+
const status = await deps.api.convert.status(projectId);
|
|
151
|
+
if (status.pendingInquiry != null)
|
|
152
|
+
return status.pendingInquiry;
|
|
151
153
|
}
|
|
152
154
|
catch (e) {
|
|
153
|
-
deps.log(`no question
|
|
154
|
-
return null;
|
|
155
|
+
deps.log(`no conversion question for ${projectId}: ${e.message}`);
|
|
155
156
|
}
|
|
157
|
+
return null;
|
|
156
158
|
};
|
|
157
159
|
const questionResult = (inquiry, deps, note) => ok((note != null ? `${note}\n\n` : '') + renderQuestionEnvelope(inquiry, { harness: deps.host.harness }), { questionId: inquiry.id });
|
|
158
160
|
/** A cost estimate, always with the sentence that says what it is not. */
|
|
@@ -237,7 +239,7 @@ const renderCheck = (check, conversion) => {
|
|
|
237
239
|
? 'nothing — this origin cannot be converted'
|
|
238
240
|
: conversion != null
|
|
239
241
|
? conversionNext(conversion)
|
|
240
|
-
: 'convert_project to start, then
|
|
242
|
+
: 'convert_project to start, then read conversion_status'}`);
|
|
241
243
|
return lines.join('\n');
|
|
242
244
|
};
|
|
243
245
|
const renderConversion = (view) => {
|
|
@@ -264,47 +266,20 @@ const renderConversion = (view) => {
|
|
|
264
266
|
+ ` $${STORY_BAND_MIN_USD}–$${STORY_BAND_MAX_USD} each.`);
|
|
265
267
|
}
|
|
266
268
|
// Phrased, exactly like a thrown one: the platform writes a failed stage's cause here with
|
|
267
|
-
// `describeFailure`, which for a refusal is the marker verbatim
|
|
268
|
-
//
|
|
269
|
-
// while `wait_for` on the very same run read out the sentence. One refusal, two readings.
|
|
269
|
+
// `describeFailure`, which for a refusal is the marker verbatim. Phrase the stored value the
|
|
270
|
+
// same way as a thrown refusal so every conversion status has one user-facing reading.
|
|
270
271
|
if (view.lastError != null && view.lastError !== '') {
|
|
271
272
|
lines.push(`error: ${refusalPhrase(view.lastError)}`);
|
|
272
273
|
}
|
|
273
274
|
lines.push(`next: ${conversionNext(view)}`);
|
|
274
275
|
return lines.join('\n');
|
|
275
276
|
};
|
|
276
|
-
/**
|
|
277
|
-
* What to call after reading a conversion.
|
|
278
|
-
*
|
|
279
|
-
* Derived from the STATUS first and the stage second, because the two say different things: a
|
|
280
|
-
* stage says how far the conversion has got, and only the status says whether the platform is
|
|
281
|
-
* working, waiting for a person, or waiting for a decision that is the user's.
|
|
282
|
-
*/
|
|
283
|
-
const conversionNext = (view) => {
|
|
284
|
-
switch (view.status) {
|
|
285
|
-
case ConversionStatus.Running:
|
|
286
|
-
return 'wait_for on the job, or conversion_status again';
|
|
287
|
-
case ConversionStatus.Waiting:
|
|
288
|
-
return 'next_question — this conversion needs a decision from the person you work for';
|
|
289
|
-
case ConversionStatus.Awaiting:
|
|
290
|
-
return `proceed_conversion { "decision": "${decisionFor(view.stage)}" } to go on, or`
|
|
291
|
-
+ ` { "decision": "${ConversionDecision.Leave}" } to keep what it has produced`;
|
|
292
|
-
case ConversionStatus.Failed:
|
|
293
|
-
return `proceed_conversion { "decision": "${ConversionDecision.Retry}" } once the cause is addressed`;
|
|
294
|
-
case ConversionStatus.Done:
|
|
295
|
-
return 'nothing — this conversion is finished. purge_origin deletes the original sources.';
|
|
296
|
-
case ConversionStatus.Cancelled:
|
|
297
|
-
return 'nothing — this conversion was cancelled';
|
|
298
|
-
default:
|
|
299
|
-
return 'convert_project to start it';
|
|
300
|
-
}
|
|
301
|
-
};
|
|
302
277
|
/**
|
|
303
278
|
* Everything a parent agent can ask the platform to do.
|
|
304
279
|
*
|
|
305
280
|
* Two rules shape the whole list. Every tool answers inside the strictest host's per-tool ceiling,
|
|
306
|
-
* so anything that takes minutes returns
|
|
307
|
-
*
|
|
281
|
+
* so anything that takes minutes returns its current domain status and continues server-side. And
|
|
282
|
+
* every tool that cannot work in
|
|
308
283
|
* a given mode is HIDDEN rather than failing, so the catalogue a parent reads is exactly the set
|
|
309
284
|
* of things that work for it.
|
|
310
285
|
*/
|
|
@@ -364,12 +339,12 @@ export const catalogue = [
|
|
|
364
339
|
// a delegated session performs all of them, an ordinary one performs a conversion's. Both
|
|
365
340
|
// collect them the same way, so both are told to call next_task.
|
|
366
341
|
+ (performsModelTasks(deps.host)
|
|
367
|
-
? '\n\nThis session runs the platform\'s model calls on YOUR side. Whenever a
|
|
368
|
-
+ '
|
|
342
|
+
? '\n\nThis session runs the platform\'s model calls on YOUR side. Whenever a domain status'
|
|
343
|
+
+ ' reports waiting for a model task, call next_task.'
|
|
369
344
|
: sessionCapable(deps.host)
|
|
370
345
|
? '\n\nThe platform performs its own model calls for stories and free flight. A'
|
|
371
|
-
+ ' CONVERSION\'s calls are yours by default. Whenever a
|
|
372
|
-
+ ' model
|
|
346
|
+
+ ' CONVERSION\'s calls are yours by default. Whenever a domain status reports'
|
|
347
|
+
+ ' waiting for a model task, call next_task.'
|
|
373
348
|
: ''), { tiers, subagents, effortControl, roles: byTier });
|
|
374
349
|
},
|
|
375
350
|
},
|
|
@@ -438,36 +413,17 @@ export const catalogue = [
|
|
|
438
413
|
return ok(lines.join('\n'));
|
|
439
414
|
},
|
|
440
415
|
},
|
|
441
|
-
{
|
|
442
|
-
name: 'wait_for',
|
|
443
|
-
title: 'Wait for a job',
|
|
444
|
-
description: `Poll one job for up to ${JOB_POLL_MAX_SEC} seconds. Returns as soon as it finishes or`
|
|
445
|
-
+ ' becomes blocked; call again while it is still running.',
|
|
446
|
-
input: {
|
|
447
|
-
jobId: z.string(),
|
|
448
|
-
projectId: z.string().optional(),
|
|
449
|
-
maxWaitSec: z.number().int().min(0).max(JOB_POLL_MAX_SEC).optional(),
|
|
450
|
-
},
|
|
451
|
-
availability: anyHost,
|
|
452
|
-
run: async (args, deps) => {
|
|
453
|
-
const project = projectOf(args, deps);
|
|
454
|
-
const wait = Math.min(args.maxWaitSec ?? JOB_POLL_MAX_SEC, JOB_POLL_MAX_SEC);
|
|
455
|
-
const job = await deps.api.project.job(project, args.jobId, wait);
|
|
456
|
-
return jobResult(job);
|
|
457
|
-
},
|
|
458
|
-
},
|
|
459
416
|
{
|
|
460
417
|
name: 'create_project',
|
|
461
418
|
title: 'Start a project from a description',
|
|
462
419
|
description: 'Describe the application in a sentence or two. The platform writes a specification, names it'
|
|
463
|
-
+ ' and drafts a vision. Returns
|
|
464
|
-
+ ' confirm_project.',
|
|
420
|
+
+ ' and drafts a vision. Returns the project status; read the draft and call confirm_project.',
|
|
465
421
|
input: { prompt: z.string().min(1) },
|
|
466
422
|
availability: anyHost,
|
|
467
423
|
run: async (args, deps) => {
|
|
468
|
-
const
|
|
469
|
-
deps.attach(
|
|
470
|
-
return
|
|
424
|
+
const status = await deps.api.project.create(args.prompt, deps.host.target === ConnectTarget.Local ? ConnectTarget.Local : ConnectTarget.Cloud);
|
|
425
|
+
deps.attach(status.project.id);
|
|
426
|
+
return projectResult(status);
|
|
471
427
|
},
|
|
472
428
|
},
|
|
473
429
|
{
|
|
@@ -475,7 +431,7 @@ export const catalogue = [
|
|
|
475
431
|
title: 'Accept the specification and build the application',
|
|
476
432
|
description: 'Confirm the drafted project, optionally editing what the analysis produced. This is what'
|
|
477
433
|
+ ' starts the build: the template lands, dependencies install, the whole application is'
|
|
478
|
-
+ ' drawn. Returns
|
|
434
|
+
+ ' drawn. Returns the project status while the server-side run continues.',
|
|
479
435
|
input: {
|
|
480
436
|
projectId: z.string().optional(),
|
|
481
437
|
name: z.string().optional(),
|
|
@@ -492,14 +448,14 @@ export const catalogue = [
|
|
|
492
448
|
// whose connector has not filed a session yet is not queued for later — a local target
|
|
493
449
|
// answers it with `ConnectSessionGone` and the step fails.
|
|
494
450
|
await ensureSession(deps, project);
|
|
495
|
-
const
|
|
451
|
+
const status = await deps.api.project.confirm(project, {
|
|
496
452
|
...(typeof args.name === 'string' ? { name: args.name } : {}),
|
|
497
453
|
...(typeof args.description === 'string' ? { description: args.description } : {}),
|
|
498
454
|
...(typeof args.specification === 'string' ? { specification: args.specification } : {}),
|
|
499
455
|
...(typeof args.vision === 'string' ? { vision: args.vision } : {}),
|
|
500
456
|
...(typeof args.designSystem === 'string' ? { designSystem: args.designSystem } : {}),
|
|
501
457
|
});
|
|
502
|
-
return
|
|
458
|
+
return projectResult(status);
|
|
503
459
|
},
|
|
504
460
|
},
|
|
505
461
|
{
|
|
@@ -598,8 +554,7 @@ export const catalogue = [
|
|
|
598
554
|
run: async (args, deps) => {
|
|
599
555
|
const project = projectOf(args, deps);
|
|
600
556
|
await ensureSession(deps, project);
|
|
601
|
-
|
|
602
|
-
return jobResult(job);
|
|
557
|
+
return projectResult(await deps.api.project.reinit(project));
|
|
603
558
|
},
|
|
604
559
|
},
|
|
605
560
|
{
|
|
@@ -656,7 +611,7 @@ export const catalogue = [
|
|
|
656
611
|
const project = projectOf(args, deps);
|
|
657
612
|
// Formatting reads the target's file-backed entities before it persists the story. A local
|
|
658
613
|
// project therefore needs its connector back after an MCP restart even though this tool does
|
|
659
|
-
// not itself
|
|
614
|
+
// not itself start a long-running operation.
|
|
660
615
|
await ensureSession(deps, project);
|
|
661
616
|
// The narrative goes as written and with no area: rewriting it and deciding the area is the
|
|
662
617
|
// platform's, done on the way in for a person's story — a connector that guessed an area
|
|
@@ -724,7 +679,7 @@ export const catalogue = [
|
|
|
724
679
|
name: 'develop_story',
|
|
725
680
|
title: 'Implement a user story',
|
|
726
681
|
description: 'Ask the platform to design and build one story: its screens, its data, its endpoints, its'
|
|
727
|
-
+ ' navigation. This is the main event and takes many minutes. Returns
|
|
682
|
+
+ ' navigation. This is the main event and takes many minutes. Returns the story status.',
|
|
728
683
|
input: { storyId: z.string(), projectId: z.string().optional() },
|
|
729
684
|
availability: anyHost,
|
|
730
685
|
run: async (args, deps) => {
|
|
@@ -745,40 +700,37 @@ export const catalogue = [
|
|
|
745
700
|
catch (e) {
|
|
746
701
|
if (!(e instanceof CommitTimeout))
|
|
747
702
|
throw e;
|
|
748
|
-
// The move is durable and only its commit is late, so the
|
|
703
|
+
// The move is durable and only its commit is late, so the story status is still the answer —
|
|
749
704
|
// waiting out the host's ceiling here would report a slow platform as a broken server.
|
|
750
705
|
deps.log(`develop_story: the start of ${card.code ?? card.id} has not committed yet;`
|
|
751
|
-
+ ' answering from
|
|
706
|
+
+ ' answering from story status');
|
|
752
707
|
}
|
|
753
|
-
return
|
|
708
|
+
return storyResult(await deps.api.story.status(project, card.id));
|
|
754
709
|
},
|
|
755
710
|
},
|
|
756
711
|
{
|
|
757
712
|
name: 'story_status',
|
|
758
713
|
title: 'What happened to a story',
|
|
759
|
-
description: 'One story
|
|
714
|
+
description: 'One story, its development run, and any warning explaining a failure.',
|
|
760
715
|
input: { storyId: z.string(), projectId: z.string().optional() },
|
|
761
716
|
availability: anyHost,
|
|
762
717
|
run: async (args, deps) => {
|
|
763
|
-
const
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
return ok(`${card.code ?? card.id} · ${card.status}`
|
|
767
|
-
+ (warning != null && warning !== '' ? `\nwarning: ${String(warning)}` : ''), card);
|
|
718
|
+
const project = projectOf(args, deps);
|
|
719
|
+
const card = await resolveStory(deps, project, args.storyId);
|
|
720
|
+
return storyResult(await deps.api.story.status(project, card.id));
|
|
768
721
|
},
|
|
769
722
|
},
|
|
770
723
|
{
|
|
771
724
|
name: 'modify_project',
|
|
772
725
|
title: 'Ask the agent for an open-ended change',
|
|
773
726
|
description: 'Describe a change in words and let the platform\'s own coding agent make it. For anything'
|
|
774
|
-
+ ' that is not a user story: a rename, a fix, a styling change. Returns
|
|
727
|
+
+ ' that is not a user story: a rename, a fix, a styling change. Returns project status.',
|
|
775
728
|
input: { prompt: z.string().min(1), projectId: z.string().optional() },
|
|
776
729
|
availability: anyHost,
|
|
777
730
|
run: async (args, deps) => {
|
|
778
731
|
const project = projectOf(args, deps);
|
|
779
732
|
await ensureSession(deps, project);
|
|
780
|
-
|
|
781
|
-
return jobResult(job);
|
|
733
|
+
return projectResult(await deps.api.project.modify(project, args.prompt));
|
|
782
734
|
},
|
|
783
735
|
},
|
|
784
736
|
{
|
|
@@ -789,10 +741,7 @@ export const catalogue = [
|
|
|
789
741
|
availability: anyHost,
|
|
790
742
|
run: async (args, deps) => {
|
|
791
743
|
const state = await deps.api.pipeline.state(projectOf(args, deps), args.runId);
|
|
792
|
-
return
|
|
793
|
-
+ (state.step != null ? ` · stopped at ${String(state.step)}` : '')
|
|
794
|
-
// A run stops on the same refusals a call is thrown, and the row keeps the cause as text.
|
|
795
|
-
+ (state.error != null ? `\nerror: ${refusalPhrase(String(state.error))}` : ''), state);
|
|
744
|
+
return pipelineResult(state);
|
|
796
745
|
},
|
|
797
746
|
},
|
|
798
747
|
{
|
|
@@ -809,10 +758,10 @@ export const catalogue = [
|
|
|
809
758
|
run: async (args, deps) => {
|
|
810
759
|
const project = projectOf(args, deps);
|
|
811
760
|
await ensureSession(deps, project);
|
|
812
|
-
const
|
|
761
|
+
const status = await deps.api.pipeline.resume(project, args.runId, {
|
|
813
762
|
...(typeof args.from === 'string' ? { from: args.from } : {}),
|
|
814
763
|
});
|
|
815
|
-
return
|
|
764
|
+
return pipelineResult(status);
|
|
816
765
|
},
|
|
817
766
|
},
|
|
818
767
|
{
|
|
@@ -820,8 +769,8 @@ export const catalogue = [
|
|
|
820
769
|
title: 'Get the next model call to perform',
|
|
821
770
|
description: 'The platform hands you model calls to perform: a conversion\'s by default, and everything'
|
|
822
771
|
+ ' else when this session runs in the delegated mode. Returns one task with instructions for'
|
|
823
|
-
+ ' running it in a clean subagent, or says there is nothing yet. Call it whenever a
|
|
824
|
-
+ '
|
|
772
|
+
+ ' running it in a clean subagent, or says there is nothing yet. Call it whenever a domain'
|
|
773
|
+
+ ' status says it is waiting for a model task, and keep calling until it says none.',
|
|
825
774
|
input: {
|
|
826
775
|
maxWaitSec: z.number().int().min(0).max(45).optional(),
|
|
827
776
|
taskId: z.string().optional()
|
|
@@ -837,7 +786,7 @@ export const catalogue = [
|
|
|
837
786
|
// Asking for one by id re-reads it rather than taking a new one. A task is handed out once
|
|
838
787
|
// and the platform waits on it for up to 45 minutes, so a parent that lost the envelope —
|
|
839
788
|
// a compacted conversation, a subagent that died before answering — otherwise has no way
|
|
840
|
-
// back to it and the
|
|
789
|
+
// back to it and the run waits until the deadline for no reason.
|
|
841
790
|
if (typeof args.taskId === 'string') {
|
|
842
791
|
const known = session.taskById(args.taskId);
|
|
843
792
|
if (known == null) {
|
|
@@ -856,8 +805,8 @@ export const catalogue = [
|
|
|
856
805
|
+ ` ${outstanding.map(one => one.id).join(', ')}. Submit the answer with`
|
|
857
806
|
+ ' submit_task_result, or call next_task with that taskId to read it again.');
|
|
858
807
|
}
|
|
859
|
-
return ok('No task right now.
|
|
860
|
-
+ '
|
|
808
|
+
return ok('No task right now. Read the matching project, story, conversion, or pipeline status;'
|
|
809
|
+
+ ' call next_task again only while it reports waiting for a model task.');
|
|
861
810
|
}
|
|
862
811
|
return ok(renderTaskEnvelope(task, { harness: deps.host.harness }), { taskId: task.id });
|
|
863
812
|
},
|
|
@@ -889,20 +838,18 @@ export const catalogue = [
|
|
|
889
838
|
const next = session.pendingTasks();
|
|
890
839
|
return ok(next > 0
|
|
891
840
|
? `Accepted. ${next} more task(s) waiting — call next_task.`
|
|
892
|
-
: 'Accepted.
|
|
841
|
+
: 'Accepted. Read the matching project, story, conversion, or pipeline status.');
|
|
893
842
|
},
|
|
894
843
|
},
|
|
895
844
|
{
|
|
896
845
|
name: 'next_question',
|
|
897
846
|
title: 'Get the question the platform is asking',
|
|
898
847
|
description: 'The platform sometimes needs a decision only the person you are working for can make.'
|
|
899
|
-
+ ' Returns one question to put to them, or says there is none.
|
|
900
|
-
+ '
|
|
848
|
+
+ ' Returns one question to put to them, or says there is none. Domain status responses also'
|
|
849
|
+
+ ' include parked questions directly.',
|
|
901
850
|
input: {
|
|
902
851
|
maxWaitSec: z.number().int().min(0).max(45).optional(),
|
|
903
852
|
questionId: z.string().optional().describe('Re-read a question you were already given.'),
|
|
904
|
-
jobId: z.string().optional()
|
|
905
|
-
.describe('The job that reported "blocked on: question", if you have its id.'),
|
|
906
853
|
projectId: z.string().optional(),
|
|
907
854
|
},
|
|
908
855
|
// Not `performsModelTasks`: a question has nothing to do with who performs the model calls,
|
|
@@ -912,12 +859,11 @@ export const catalogue = [
|
|
|
912
859
|
run: async (args, deps) => {
|
|
913
860
|
const session = await deps.session();
|
|
914
861
|
const project = projectOrNull(args, deps);
|
|
915
|
-
const jobId = typeof args.jobId === 'string' ? args.jobId : undefined;
|
|
916
862
|
// Asking for one by id re-reads it rather than taking a new one — the same reason
|
|
917
863
|
// `next_task` does: a parent that lost the envelope has no other way back to it.
|
|
918
864
|
if (typeof args.questionId === 'string') {
|
|
919
865
|
const known = session.questionById(args.questionId)
|
|
920
|
-
?? (project != null ? await parkedQuestion(deps, project
|
|
866
|
+
?? (project != null ? await parkedQuestion(deps, project) : null);
|
|
921
867
|
if (known == null || known.id !== args.questionId) {
|
|
922
868
|
return fail(`No question ${args.questionId} is waiting. Call next_question with no id.`);
|
|
923
869
|
}
|
|
@@ -935,12 +881,12 @@ export const catalogue = [
|
|
|
935
881
|
}
|
|
936
882
|
// Nothing queued here, which does not mean nothing is being asked: a run that parked while
|
|
937
883
|
// this connector was away is waiting on a question whose operation has long expired.
|
|
938
|
-
const parked = project != null ? await parkedQuestion(deps, project
|
|
884
|
+
const parked = project != null ? await parkedQuestion(deps, project) : null;
|
|
939
885
|
if (parked != null) {
|
|
940
886
|
return questionResult(parked, deps, 'This run parked on a question before this session attached. It is still open:');
|
|
941
887
|
}
|
|
942
|
-
return ok('No question right now.
|
|
943
|
-
+ '
|
|
888
|
+
return ok('No question right now. Read the matching domain status and answer any pendingInquiry it'
|
|
889
|
+
+ ' returns; call next_question again only while it reports waiting for a person.');
|
|
944
890
|
},
|
|
945
891
|
},
|
|
946
892
|
{
|
|
@@ -954,11 +900,6 @@ export const catalogue = [
|
|
|
954
900
|
answer: z.union([z.string(), z.array(z.string())]).optional(),
|
|
955
901
|
text: z.string().optional().describe('What they said, where the question takes words.'),
|
|
956
902
|
declined: z.boolean().optional().describe('Nobody could decide this.'),
|
|
957
|
-
// Taken here for the same reason `next_question` takes it, and it has to be the SAME reach:
|
|
958
|
-
// a question this tool cannot find is refused after a person has already answered it, and
|
|
959
|
-
// the parent is sent back to `next_question`, which would offer it again through the job.
|
|
960
|
-
jobId: z.string().optional()
|
|
961
|
-
.describe('The job that reported "blocked on: question", if you have its id.'),
|
|
962
903
|
projectId: z.string().optional(),
|
|
963
904
|
},
|
|
964
905
|
availability: sessionCapable,
|
|
@@ -966,11 +907,10 @@ export const catalogue = [
|
|
|
966
907
|
const session = await deps.session();
|
|
967
908
|
const questionId = args.questionId;
|
|
968
909
|
const project = projectOrNull(args, deps);
|
|
969
|
-
const jobId = typeof args.jobId === 'string' ? args.jobId : undefined;
|
|
970
910
|
// The question this session is holding, if it still is. That is what decides HOW the answer
|
|
971
911
|
// travels: an operation the platform is waiting on, or the question's own id.
|
|
972
912
|
const held = session.questionById(questionId);
|
|
973
|
-
const inquiry = held ?? (project != null ? await parkedQuestion(deps, project
|
|
913
|
+
const inquiry = held ?? (project != null ? await parkedQuestion(deps, project) : null);
|
|
974
914
|
if (inquiry == null || inquiry.id !== questionId) {
|
|
975
915
|
return fail(`No question ${questionId} is waiting. Call next_question for the current one.`);
|
|
976
916
|
}
|
|
@@ -989,7 +929,7 @@ export const catalogue = [
|
|
|
989
929
|
}
|
|
990
930
|
await deps.api.inquiry.answer(project, questionId, answer);
|
|
991
931
|
}
|
|
992
|
-
return ok('Recorded.
|
|
932
|
+
return ok('Recorded. Read the matching project, story, conversion, or pipeline status.');
|
|
993
933
|
},
|
|
994
934
|
},
|
|
995
935
|
{
|
|
@@ -1018,7 +958,7 @@ export const catalogue = [
|
|
|
1018
958
|
title: 'Convert an application you already have',
|
|
1019
959
|
description: 'Bring an existing application onto the platform: it reads the code, restores the'
|
|
1020
960
|
+ ' specification and the user stories nobody wrote down, and rebuilds it on the platform\'s'
|
|
1021
|
-
+ ' stack. The original is kept beside it. Returns
|
|
961
|
+
+ ' stack. The original is kept beside it. Returns conversion status and stops at your decision after'
|
|
1022
962
|
+ ' each stage.',
|
|
1023
963
|
input: {
|
|
1024
964
|
projectId: z.string().optional().describe('Convert into a project that already exists.'),
|
|
@@ -1033,7 +973,7 @@ export const catalogue = [
|
|
|
1033
973
|
const named = typeof args.projectId === 'string' ? args.projectId : deps.attached();
|
|
1034
974
|
if (named != null) {
|
|
1035
975
|
await ensureSession(deps, named);
|
|
1036
|
-
return
|
|
976
|
+
return conversionResult(await deps.api.convert.start(named));
|
|
1037
977
|
}
|
|
1038
978
|
const repoUrl = typeof args.repoUrl === 'string' && args.repoUrl.trim() !== ''
|
|
1039
979
|
? args.repoUrl.trim()
|
|
@@ -1042,7 +982,7 @@ export const catalogue = [
|
|
|
1042
982
|
return fail('Nothing to convert. Name a project, attach one, run the connector in the directory you'
|
|
1043
983
|
+ ' want converted, or give a repoUrl.');
|
|
1044
984
|
}
|
|
1045
|
-
const
|
|
985
|
+
const status = await deps.api.convert.create({
|
|
1046
986
|
...(typeof args.name === 'string' ? { name: args.name } : {}),
|
|
1047
987
|
...(typeof args.about === 'string' ? { about: args.about } : {}),
|
|
1048
988
|
// A NAMED repository outranks the directory this connector runs in. A stdio connector
|
|
@@ -1062,9 +1002,9 @@ export const catalogue = [
|
|
|
1062
1002
|
},
|
|
1063
1003
|
}),
|
|
1064
1004
|
});
|
|
1065
|
-
deps.attach(
|
|
1066
|
-
await ensureSession(deps,
|
|
1067
|
-
return
|
|
1005
|
+
deps.attach(status.projectId);
|
|
1006
|
+
await ensureSession(deps, status.projectId);
|
|
1007
|
+
return conversionResult(await deps.api.convert.start(status.projectId));
|
|
1068
1008
|
}),
|
|
1069
1009
|
},
|
|
1070
1010
|
{
|
|
@@ -1072,7 +1012,7 @@ export const catalogue = [
|
|
|
1072
1012
|
title: 'Decide what a conversion does next',
|
|
1073
1013
|
description: 'A conversion stops after each stage and waits for a decision: analyze what was read,'
|
|
1074
1014
|
+ ' extract the user stories, implement them, leave it as it stands, retry a stage that'
|
|
1075
|
-
+ ' failed, or cancel. Returns
|
|
1015
|
+
+ ' failed, or cancel. Returns the conversion status.',
|
|
1076
1016
|
input: {
|
|
1077
1017
|
decision: z.enum(Object.values(ConversionDecision)),
|
|
1078
1018
|
projectId: z.string().optional(),
|
|
@@ -1082,8 +1022,8 @@ export const catalogue = [
|
|
|
1082
1022
|
run: async (args, deps) => await answering(deps, 'proceed_conversion', async () => {
|
|
1083
1023
|
const project = projectOf(args, deps);
|
|
1084
1024
|
await ensureSession(deps, project);
|
|
1085
|
-
const
|
|
1086
|
-
return
|
|
1025
|
+
const status = await deps.api.convert.proceed(project, args.decision, typeof args.note === 'string' ? args.note : undefined);
|
|
1026
|
+
return conversionResult(status);
|
|
1087
1027
|
}),
|
|
1088
1028
|
},
|
|
1089
1029
|
{
|
|
@@ -1117,7 +1057,7 @@ export const catalogue = [
|
|
|
1117
1057
|
}
|
|
1118
1058
|
const project = projectOf(args, deps);
|
|
1119
1059
|
await ensureSession(deps, project);
|
|
1120
|
-
return
|
|
1060
|
+
return conversionResult(await deps.api.convert.purge(project));
|
|
1121
1061
|
}),
|
|
1122
1062
|
},
|
|
1123
1063
|
{
|