gestalt-mobile 0.17.3 → 0.18.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/README.md +5 -1
- package/dist/client/assets/index-CJBtrNWw.css +1 -0
- package/dist/client/assets/index-D4ZAKUN3.js +27 -0
- package/dist/client/index.html +2 -2
- package/dist/server/server/app.js +6 -0
- package/dist/server/server/composition.js +383 -26
- package/dist/server/server/features/agent-activity/model.js +197 -0
- package/dist/server/server/features/agent-activity/registry.js +155 -0
- package/dist/server/server/features/autopilot/application/policy.js +55 -0
- package/dist/server/server/features/autopilot/application/ports.js +6 -0
- package/dist/server/server/features/autopilot/application/service.js +542 -0
- package/dist/server/server/features/autopilot/domain/autopilot-session.js +40 -0
- package/dist/server/server/features/autopilot/register-routes.js +9 -0
- package/dist/server/server/features/autopilot/toggle/endpoint.js +32 -0
- package/dist/server/server/features/org-plan-attention/application/ports.js +6 -0
- package/dist/server/server/features/org-plan-attention/get-active/endpoint.js +22 -0
- package/dist/server/server/features/org-plan-attention/register-routes.js +11 -0
- package/dist/server/server/features/org-plan-attention/resolve/endpoint.js +42 -0
- package/dist/server/server/features/plans/application/parse-supervised-plan.js +4 -0
- package/dist/server/server/features/sessions/get-history/endpoint.js +62 -2
- package/dist/server/server/features/sessions/get-history/history-mapper.js +17 -5
- package/dist/server/server/features/sessions/get-session/endpoint.js +3 -1
- package/dist/server/server/features/sessions/interaction/kind.js +1 -0
- package/dist/server/server/features/sessions/interaction/response-validator.js +5 -1
- package/dist/server/server/features/sessions/list-sessions/endpoint.js +2 -0
- package/dist/server/server/features/sessions/model/relay-session.js +3 -0
- package/dist/server/server/features/sessions/refresh-activity/endpoint.js +14 -0
- package/dist/server/server/features/sessions/register-routes.js +15 -2
- package/dist/server/server/features/sessions/restore-session/endpoint.js +21 -5
- package/dist/server/server/features/skills/list-available/endpoint.js +3 -4
- package/dist/server/server/features/skills/model/skill-profile.js +13 -5
- package/dist/server/server/platform/codex/activity-facts.js +88 -0
- package/dist/server/server/platform/codex/server-request.js +12 -4
- package/dist/server/server/platform/codex/session-runtime.js +91 -8
- package/dist/server/server/platform/persistence/migrate.js +16 -1
- package/dist/server/server/platform/persistence/sqlite-autopilot-store.js +151 -0
- package/dist/server/server/platform/persistence/sqlite-event-journal.js +92 -4
- package/dist/server/server/platform/persistence/sqlite-pending-interaction-store.js +57 -8
- package/dist/server/server/platform/persistence/sqlite-session-repository.js +5 -2
- package/dist/server/server/platform/plans/filesystem-workspace-plan-catalog.js +43 -12
- package/dist/server/shared/contracts/org-plan-attention.js +101 -0
- package/package.json +1 -1
- package/dist/client/assets/index-Ba_4zoY1.js +0 -25
- package/dist/client/assets/index-e2lJ5XqL.css +0 -1
- package/dist/server/server/platform/plans/org-plan-command-validator.js +0 -62
|
@@ -9,14 +9,12 @@ import { parseSupervisedPlan } from '../../features/plans/application/parse-supe
|
|
|
9
9
|
const maximumBytes = 1_048_576;
|
|
10
10
|
/**
|
|
11
11
|
* Passive access to every regular `.org` file below a workspace. Symlinks are
|
|
12
|
-
* never followed
|
|
13
|
-
*
|
|
12
|
+
* never followed. Supported supervised plans include a browser preview; other
|
|
13
|
+
* Org files remain visible in the catalog without one.
|
|
14
14
|
*/
|
|
15
15
|
export class FilesystemWorkspacePlanCatalog {
|
|
16
|
-
validator;
|
|
17
16
|
filesystem;
|
|
18
|
-
constructor(
|
|
19
|
-
this.validator = validator;
|
|
17
|
+
constructor(filesystem = { lstat, readdir, readFile, realpath, stat }) {
|
|
20
18
|
this.filesystem = filesystem;
|
|
21
19
|
}
|
|
22
20
|
async list(workspacePath) {
|
|
@@ -26,10 +24,21 @@ export class FilesystemWorkspacePlanCatalog {
|
|
|
26
24
|
const planNames = await this.discover(workspace);
|
|
27
25
|
const entries = [];
|
|
28
26
|
for (const planName of planNames) {
|
|
29
|
-
const
|
|
30
|
-
if (
|
|
27
|
+
const candidate = await this.readCandidate(workspace, planName);
|
|
28
|
+
if (candidate.kind === 'missing')
|
|
31
29
|
continue;
|
|
32
|
-
|
|
30
|
+
if (candidate.kind === 'unavailable') {
|
|
31
|
+
entries.push(toFallbackEntry(planName));
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const parsed = parseSupervisedPlan({
|
|
35
|
+
source: candidate.source,
|
|
36
|
+
planPath: candidate.canonicalPath,
|
|
37
|
+
workspacePath: workspace,
|
|
38
|
+
});
|
|
39
|
+
entries.push(parsed.kind === 'available'
|
|
40
|
+
? toEntry(planName, parsed.plan)
|
|
41
|
+
: toFallbackEntry(planName, candidate.source));
|
|
33
42
|
}
|
|
34
43
|
return entries;
|
|
35
44
|
}
|
|
@@ -94,6 +103,17 @@ export class FilesystemWorkspacePlanCatalog {
|
|
|
94
103
|
return plans.sort((left, right) => left.localeCompare(right));
|
|
95
104
|
}
|
|
96
105
|
async readFromWorkspace(workspace, planName) {
|
|
106
|
+
const candidate = await this.readCandidate(workspace, planName);
|
|
107
|
+
if (candidate.kind !== 'readable')
|
|
108
|
+
return candidate;
|
|
109
|
+
const parsed = parseSupervisedPlan({
|
|
110
|
+
source: candidate.source,
|
|
111
|
+
planPath: candidate.canonicalPath,
|
|
112
|
+
workspacePath: workspace,
|
|
113
|
+
});
|
|
114
|
+
return parsed.kind === 'available' ? parsed : { kind: 'unavailable' };
|
|
115
|
+
}
|
|
116
|
+
async readCandidate(workspace, planName) {
|
|
97
117
|
if (!isPlanPath(planName))
|
|
98
118
|
return { kind: 'missing' };
|
|
99
119
|
const path = resolve(workspace, ...planName.split('/'));
|
|
@@ -108,8 +128,6 @@ export class FilesystemWorkspacePlanCatalog {
|
|
|
108
128
|
toPlanName(relative(workspace, canonical)) !== planName)
|
|
109
129
|
return { kind: 'unavailable' };
|
|
110
130
|
const source = await this.filesystem.readFile(canonical, 'utf8');
|
|
111
|
-
if (!(await this.validator.validate(workspace, canonical)))
|
|
112
|
-
return { kind: 'unavailable' };
|
|
113
131
|
const after = await this.filesystem.stat(canonical);
|
|
114
132
|
if (!after.isFile() ||
|
|
115
133
|
after.size !== before.size ||
|
|
@@ -117,8 +135,7 @@ export class FilesystemWorkspacePlanCatalog {
|
|
|
117
135
|
after.dev !== before.dev ||
|
|
118
136
|
after.mtimeMs !== before.mtimeMs)
|
|
119
137
|
return { kind: 'unavailable' };
|
|
120
|
-
|
|
121
|
-
return parsed.kind === 'available' ? parsed : { kind: 'unavailable' };
|
|
138
|
+
return { kind: 'readable', source, canonicalPath: canonical };
|
|
122
139
|
}
|
|
123
140
|
catch (error) {
|
|
124
141
|
return error.code === 'ENOENT'
|
|
@@ -153,8 +170,22 @@ function toEntry(planName, plan) {
|
|
|
153
170
|
...(plan.subtitle === undefined ? {} : { subtitle: plan.subtitle }),
|
|
154
171
|
...(plan.date === undefined ? {} : { date: plan.date }),
|
|
155
172
|
...(plan.keywords === undefined ? {} : { keywords: plan.keywords }),
|
|
173
|
+
previewAvailable: true,
|
|
156
174
|
totalSteps: plan.totalSteps,
|
|
157
175
|
doneSteps: plan.doneSteps,
|
|
158
176
|
allDone: plan.allDone,
|
|
159
177
|
};
|
|
160
178
|
}
|
|
179
|
+
function toFallbackEntry(planName, source) {
|
|
180
|
+
const declaredTitle = source
|
|
181
|
+
?.replace(/\r\n?/g, '\n')
|
|
182
|
+
.split('\n')
|
|
183
|
+
.map((line) => /^#\+TITLE:(?:[ \t](.*))?$/i.exec(line)?.[1]?.trim())
|
|
184
|
+
.find((title) => title);
|
|
185
|
+
const filename = planName.split('/').at(-1) ?? planName;
|
|
186
|
+
return {
|
|
187
|
+
planName,
|
|
188
|
+
title: declaredTitle ?? filename.slice(0, -'.org'.length),
|
|
189
|
+
previewAvailable: false,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2026 Dyne.org foundation
|
|
3
|
+
* Designed by Denis Roio <jaromil@dyne.org>
|
|
4
|
+
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
*/
|
|
6
|
+
/** Versioned, bounded contract consumed by supervised Org Plan roles. */
|
|
7
|
+
export const GESTALT_ORG_PLAN_ATTENTION_TOOL_NAME = 'gestalt_org_plan_attention';
|
|
8
|
+
export const orgPlanAttentionReasons = [
|
|
9
|
+
'planChange',
|
|
10
|
+
'hardBlock',
|
|
11
|
+
'missingDependency',
|
|
12
|
+
'permissionRequired',
|
|
13
|
+
'externalState',
|
|
14
|
+
'materialAmbiguity',
|
|
15
|
+
];
|
|
16
|
+
export const orgPlanAttentionResumeConditions = [
|
|
17
|
+
'userGuidance',
|
|
18
|
+
'planRevision',
|
|
19
|
+
'dependencyInstalled',
|
|
20
|
+
'permissionGranted',
|
|
21
|
+
'externalStateChanged',
|
|
22
|
+
];
|
|
23
|
+
export const gestaltOrgPlanAttentionDynamicTool = {
|
|
24
|
+
type: 'function',
|
|
25
|
+
name: GESTALT_ORG_PLAN_ATTENTION_TOOL_NAME,
|
|
26
|
+
description: 'Declare a genuine, durable human-attention requirement for a supervised Org Plan. Use only when progress cannot continue safely without the requested bounded human action. Do not include error stacks, environment values, plan contents, or unbounded prose.',
|
|
27
|
+
inputSchema: {
|
|
28
|
+
type: 'object',
|
|
29
|
+
additionalProperties: false,
|
|
30
|
+
required: ['reason', 'summary', 'requestedAction', 'resumeCondition'],
|
|
31
|
+
properties: {
|
|
32
|
+
reason: { type: 'string', enum: orgPlanAttentionReasons },
|
|
33
|
+
summary: { type: 'string', minLength: 1, maxLength: 600 },
|
|
34
|
+
requestedAction: { type: 'string', minLength: 1, maxLength: 600 },
|
|
35
|
+
resumeCondition: { type: 'string', enum: orgPlanAttentionResumeConditions },
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
export function parseOrgPlanAttention(value) {
|
|
40
|
+
if (!isRecord(value) || Object.keys(value).length !== 4)
|
|
41
|
+
return null;
|
|
42
|
+
if (!isReason(value.reason) ||
|
|
43
|
+
!isBoundedText(value.summary, 600) ||
|
|
44
|
+
!isBoundedText(value.requestedAction, 600) ||
|
|
45
|
+
!isResumeCondition(value.resumeCondition))
|
|
46
|
+
return null;
|
|
47
|
+
return {
|
|
48
|
+
reason: value.reason,
|
|
49
|
+
summary: value.summary,
|
|
50
|
+
requestedAction: value.requestedAction,
|
|
51
|
+
resumeCondition: value.resumeCondition,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export function parseOrgPlanAttentionResponse(value) {
|
|
55
|
+
if (!isRecord(value) || !['resume', 'disableAutopilot'].includes(value.action))
|
|
56
|
+
return null;
|
|
57
|
+
if (Object.keys(value).some((key) => key !== 'action' && key !== 'guidance'))
|
|
58
|
+
return null;
|
|
59
|
+
if (value.guidance !== undefined && !isBoundedText(value.guidance, 1_000))
|
|
60
|
+
return null;
|
|
61
|
+
return {
|
|
62
|
+
action: value.action,
|
|
63
|
+
...(typeof value.guidance === 'string' ? { guidance: value.guidance } : {}),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/** The only result accepted by the held app-server dynamic-tool request. */
|
|
67
|
+
export function toOrgPlanAttentionToolResponse(response) {
|
|
68
|
+
return {
|
|
69
|
+
success: true,
|
|
70
|
+
contentItems: [{ type: 'input_text', text: JSON.stringify(response) }],
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export function isOrgPlanAttentionToolResponse(value) {
|
|
74
|
+
if (!isRecord(value) || value.success !== true || !Array.isArray(value.contentItems))
|
|
75
|
+
return false;
|
|
76
|
+
const item = value.contentItems[0];
|
|
77
|
+
if (value.contentItems.length !== 1 ||
|
|
78
|
+
!isRecord(item) ||
|
|
79
|
+
item.type !== 'input_text' ||
|
|
80
|
+
typeof item.text !== 'string')
|
|
81
|
+
return false;
|
|
82
|
+
try {
|
|
83
|
+
return parseOrgPlanAttentionResponse(JSON.parse(item.text)) !== null;
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function isReason(value) {
|
|
90
|
+
return (typeof value === 'string' && orgPlanAttentionReasons.includes(value));
|
|
91
|
+
}
|
|
92
|
+
function isResumeCondition(value) {
|
|
93
|
+
return (typeof value === 'string' &&
|
|
94
|
+
orgPlanAttentionResumeConditions.includes(value));
|
|
95
|
+
}
|
|
96
|
+
function isBoundedText(value, maximum) {
|
|
97
|
+
return typeof value === 'string' && value.trim().length > 0 && value.length <= maximum;
|
|
98
|
+
}
|
|
99
|
+
function isRecord(value) {
|
|
100
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
101
|
+
}
|