@phyzess/pappra 0.1.0-beta.12 → 0.1.0-beta.14
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 +2 -1
- package/assets/integrations/skills/pappra/references/operations.md +2 -0
- package/dist/app/collab-from.d.ts +35 -0
- package/dist/app/collab-from.js +84 -0
- package/dist/app/doctor.js +4 -2
- package/dist/app/host-mcp.d.ts +25 -0
- package/dist/app/host-mcp.js +227 -0
- package/dist/app/host-probe.d.ts +16 -0
- package/dist/app/host-probe.js +125 -0
- package/dist/app/task-pin.d.ts +23 -0
- package/dist/app/task-pin.js +113 -0
- package/dist/cli/commands/docs.js +12 -76
- package/dist/cli/commands/host.d.ts +3 -1
- package/dist/cli/commands/host.js +55 -1
- package/dist/cli/commands/mcp.d.ts +8 -0
- package/dist/cli/commands/mcp.js +13 -0
- package/dist/cli/commands/task.d.ts +10 -0
- package/dist/cli/commands/task.js +76 -0
- package/dist/cli/run.js +134 -4
- package/dist/hosts/integration/hook.js +4 -1
- package/dist/hosts/integration/pappra-extension-runtime.mjs +50 -8
- package/dist/hosts/integration/pappra-hook.mjs +50 -8
- package/dist/hosts/pilot.d.ts +77 -77
- package/dist/knowledge/scan.d.ts +30 -0
- package/dist/knowledge/scan.js +91 -0
- package/dist/mcp/server.d.ts +11 -0
- package/dist/mcp/server.js +518 -0
- package/dist/schemas/workspace.d.ts +6 -0
- package/dist/schemas/workspace.js +4 -0
- package/package.json +2 -1
- package/skills/pappra/references/operations.md +2 -0
package/dist/cli/run.js
CHANGED
|
@@ -2,6 +2,8 @@ import { parseArgs } from 'node:util';
|
|
|
2
2
|
import { getPackageInfo } from '../package-info.js';
|
|
3
3
|
import { initUsage, runInitCommand } from './commands/init.js';
|
|
4
4
|
import { onboardUsage, runOnboardCommand } from './commands/onboard.js';
|
|
5
|
+
import { mcpUsage, runMcpCommand } from './commands/mcp.js';
|
|
6
|
+
import { taskUsage, runTaskCommand } from './commands/task.js';
|
|
5
7
|
import { doctorUsage, runDoctorCommand } from './commands/doctor.js';
|
|
6
8
|
import { docsUsage, runDocsCommand } from './commands/docs.js';
|
|
7
9
|
import { checkpointUsage, resumeUsage, runCheckpointCommand, runResumeCommand, } from './commands/continuity.js';
|
|
@@ -26,6 +28,7 @@ function parseOptions(args) {
|
|
|
26
28
|
'apply-host': { type: 'boolean' },
|
|
27
29
|
'dry-run': { type: 'boolean' },
|
|
28
30
|
'print-handoff': { type: 'boolean' },
|
|
31
|
+
'auto-resume': { type: 'boolean' },
|
|
29
32
|
from: { type: 'string' },
|
|
30
33
|
tarball: { type: 'string' },
|
|
31
34
|
out: { type: 'string' },
|
|
@@ -79,6 +82,25 @@ function parseOptions(args) {
|
|
|
79
82
|
throw new Error('Use either --help or --version, not both.');
|
|
80
83
|
}
|
|
81
84
|
const command = positionals[0] ?? null;
|
|
85
|
+
if (command === 'task') {
|
|
86
|
+
if (positionals.length > 3) {
|
|
87
|
+
throw new Error('task accepts one action and an optional task id.');
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
values,
|
|
91
|
+
command,
|
|
92
|
+
docsAction: null,
|
|
93
|
+
docsArgument: null,
|
|
94
|
+
codeAction: null,
|
|
95
|
+
hostAction: null,
|
|
96
|
+
hostSubAction: null,
|
|
97
|
+
collaborationAction: null,
|
|
98
|
+
resumeTaskId: null,
|
|
99
|
+
runtimeAction: null,
|
|
100
|
+
taskAction: positionals[1] ?? null,
|
|
101
|
+
taskArgument: positionals[2] ?? null,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
82
104
|
if (command === 'docs') {
|
|
83
105
|
if (positionals.length > 3) {
|
|
84
106
|
throw new Error('Unknown command; docs accepts one action and one argument.');
|
|
@@ -90,9 +112,12 @@ function parseOptions(args) {
|
|
|
90
112
|
docsAction: positionals[1] ?? null,
|
|
91
113
|
docsArgument: positionals[2] ?? null,
|
|
92
114
|
hostAction: null,
|
|
115
|
+
hostSubAction: null,
|
|
93
116
|
collaborationAction: null,
|
|
94
117
|
resumeTaskId: null,
|
|
95
118
|
runtimeAction: null,
|
|
119
|
+
taskAction: null,
|
|
120
|
+
taskArgument: null,
|
|
96
121
|
};
|
|
97
122
|
}
|
|
98
123
|
if (command === 'resume') {
|
|
@@ -106,9 +131,12 @@ function parseOptions(args) {
|
|
|
106
131
|
docsArgument: null,
|
|
107
132
|
codeAction: null,
|
|
108
133
|
hostAction: null,
|
|
134
|
+
hostSubAction: null,
|
|
109
135
|
collaborationAction: null,
|
|
110
136
|
resumeTaskId: positionals[1] ?? null,
|
|
111
137
|
runtimeAction: null,
|
|
138
|
+
taskAction: null,
|
|
139
|
+
taskArgument: null,
|
|
112
140
|
};
|
|
113
141
|
}
|
|
114
142
|
if (command === 'code') {
|
|
@@ -122,14 +150,17 @@ function parseOptions(args) {
|
|
|
122
150
|
docsArgument: null,
|
|
123
151
|
codeAction: positionals[1] ?? null,
|
|
124
152
|
hostAction: null,
|
|
153
|
+
hostSubAction: null,
|
|
125
154
|
collaborationAction: null,
|
|
126
155
|
resumeTaskId: null,
|
|
127
156
|
runtimeAction: null,
|
|
157
|
+
taskAction: null,
|
|
158
|
+
taskArgument: null,
|
|
128
159
|
};
|
|
129
160
|
}
|
|
130
161
|
if (command === 'host') {
|
|
131
|
-
if (positionals.length >
|
|
132
|
-
throw new Error('host accepts one action
|
|
162
|
+
if (positionals.length > 3) {
|
|
163
|
+
throw new Error('host accepts one action and an optional mcp sub-action.');
|
|
133
164
|
}
|
|
134
165
|
return {
|
|
135
166
|
values,
|
|
@@ -138,9 +169,12 @@ function parseOptions(args) {
|
|
|
138
169
|
docsArgument: null,
|
|
139
170
|
codeAction: null,
|
|
140
171
|
hostAction: positionals[1] ?? null,
|
|
172
|
+
hostSubAction: positionals[2] ?? null,
|
|
141
173
|
collaborationAction: null,
|
|
142
174
|
resumeTaskId: null,
|
|
143
175
|
runtimeAction: null,
|
|
176
|
+
taskAction: null,
|
|
177
|
+
taskArgument: null,
|
|
144
178
|
};
|
|
145
179
|
}
|
|
146
180
|
if (command === 'runtime') {
|
|
@@ -154,9 +188,12 @@ function parseOptions(args) {
|
|
|
154
188
|
docsArgument: null,
|
|
155
189
|
codeAction: null,
|
|
156
190
|
hostAction: null,
|
|
191
|
+
hostSubAction: null,
|
|
157
192
|
collaborationAction: null,
|
|
158
193
|
resumeTaskId: null,
|
|
159
194
|
runtimeAction: positionals[1] ?? null,
|
|
195
|
+
taskAction: null,
|
|
196
|
+
taskArgument: null,
|
|
160
197
|
};
|
|
161
198
|
}
|
|
162
199
|
if (command === 'collab') {
|
|
@@ -170,9 +207,12 @@ function parseOptions(args) {
|
|
|
170
207
|
docsArgument: null,
|
|
171
208
|
codeAction: null,
|
|
172
209
|
hostAction: null,
|
|
210
|
+
hostSubAction: null,
|
|
173
211
|
collaborationAction: positionals[1] ?? null,
|
|
174
212
|
resumeTaskId: null,
|
|
175
213
|
runtimeAction: null,
|
|
214
|
+
taskAction: null,
|
|
215
|
+
taskArgument: null,
|
|
176
216
|
};
|
|
177
217
|
}
|
|
178
218
|
if (positionals.length > 1) {
|
|
@@ -221,6 +261,8 @@ function hasContinuityOptions(values, includeSession = true) {
|
|
|
221
261
|
(includeSession && values.session !== undefined));
|
|
222
262
|
}
|
|
223
263
|
const globalUsage = 'pappra [--help | --version] [--json]\n' +
|
|
264
|
+
'pappra task <pin|unpin|show> [taskId] [--auto-resume] [--json]\n' +
|
|
265
|
+
'pappra mcp [--root <dir>] [--help]\n' +
|
|
224
266
|
'pappra onboard [--root <dir>] [--config <file>] [--hosts <list>] [--yes]\n' +
|
|
225
267
|
' [--apply-host] [--dry-run] [--print-handoff] [--json]\n' +
|
|
226
268
|
'pappra init [--config <file> | --yes] [--apply] [--json] [--print-choices]\n' +
|
|
@@ -243,7 +285,7 @@ export async function runCli(args, output) {
|
|
|
243
285
|
failure(output, jsonRequested, 'invalid_arguments', error);
|
|
244
286
|
return 2;
|
|
245
287
|
}
|
|
246
|
-
const { values, command, docsAction, docsArgument, codeAction, hostAction, collaborationAction, resumeTaskId, runtimeAction, } = parsed;
|
|
288
|
+
const { values, command, docsAction, docsArgument, codeAction, hostAction, collaborationAction, resumeTaskId, runtimeAction, hostSubAction, taskAction, taskArgument, } = parsed;
|
|
247
289
|
const json = values.json === true;
|
|
248
290
|
const applyRequested = values.apply === true;
|
|
249
291
|
if (command !== 'init' &&
|
|
@@ -258,6 +300,10 @@ export async function runCli(args, output) {
|
|
|
258
300
|
failure(output, json, 'invalid_arguments', '--yes is only valid for init and onboard.');
|
|
259
301
|
return 2;
|
|
260
302
|
}
|
|
303
|
+
if (command !== 'task' && values['auto-resume'] === true) {
|
|
304
|
+
failure(output, json, 'invalid_arguments', '--auto-resume is only valid for task pin.');
|
|
305
|
+
return 2;
|
|
306
|
+
}
|
|
261
307
|
if (command !== 'onboard' &&
|
|
262
308
|
(values.hosts !== undefined ||
|
|
263
309
|
values['apply-host'] === true ||
|
|
@@ -297,6 +343,7 @@ export async function runCli(args, output) {
|
|
|
297
343
|
return 2;
|
|
298
344
|
}
|
|
299
345
|
if (command !== 'runtime' &&
|
|
346
|
+
command !== 'host' &&
|
|
300
347
|
(values.from !== undefined ||
|
|
301
348
|
values.tarball !== undefined ||
|
|
302
349
|
values.bind === true ||
|
|
@@ -416,6 +463,85 @@ export async function runCli(args, output) {
|
|
|
416
463
|
json,
|
|
417
464
|
}, output);
|
|
418
465
|
}
|
|
466
|
+
if (command === 'task') {
|
|
467
|
+
const action = taskAction === 'pin' || taskAction === 'unpin' || taskAction === 'show'
|
|
468
|
+
? taskAction
|
|
469
|
+
: null;
|
|
470
|
+
if (values.config !== undefined ||
|
|
471
|
+
values.apply === true ||
|
|
472
|
+
values.yes === true ||
|
|
473
|
+
values['install-runtime'] === true ||
|
|
474
|
+
values['runtime-tarball'] !== undefined ||
|
|
475
|
+
values['runtime-version'] !== undefined ||
|
|
476
|
+
values.host !== undefined ||
|
|
477
|
+
values.repo !== undefined ||
|
|
478
|
+
values.kind !== undefined ||
|
|
479
|
+
values.query !== undefined ||
|
|
480
|
+
values.root !== undefined ||
|
|
481
|
+
hasContinuityOptions(values)) {
|
|
482
|
+
failure(output, json, 'invalid_arguments', 'task accepts pin|unpin|show, an optional task id, --auto-resume, --help, and --json.');
|
|
483
|
+
return 2;
|
|
484
|
+
}
|
|
485
|
+
if (values.help) {
|
|
486
|
+
if (json) {
|
|
487
|
+
output.stdout(`${JSON.stringify({ ...info, commands: ['task'], usage: taskUsage })}\n`);
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
output.stdout(taskUsage);
|
|
491
|
+
}
|
|
492
|
+
return 0;
|
|
493
|
+
}
|
|
494
|
+
if (values.version) {
|
|
495
|
+
failure(output, json, 'invalid_arguments', '--version cannot be combined with task.');
|
|
496
|
+
return 2;
|
|
497
|
+
}
|
|
498
|
+
return runTaskCommand({
|
|
499
|
+
cwd: process.cwd(),
|
|
500
|
+
action,
|
|
501
|
+
taskId: taskArgument ?? null,
|
|
502
|
+
autoResume: values['auto-resume'] === true,
|
|
503
|
+
json,
|
|
504
|
+
}, output);
|
|
505
|
+
}
|
|
506
|
+
if (command === 'mcp') {
|
|
507
|
+
if (values.config !== undefined ||
|
|
508
|
+
values.apply === true ||
|
|
509
|
+
values.yes === true ||
|
|
510
|
+
values['install-runtime'] === true ||
|
|
511
|
+
values['runtime-tarball'] !== undefined ||
|
|
512
|
+
values['runtime-version'] !== undefined ||
|
|
513
|
+
values['include-private'] === true ||
|
|
514
|
+
values['include-archived'] === true ||
|
|
515
|
+
values['apply-host'] === true ||
|
|
516
|
+
values['dry-run'] === true ||
|
|
517
|
+
values['print-handoff'] === true ||
|
|
518
|
+
values.hosts !== undefined ||
|
|
519
|
+
values.repo !== undefined ||
|
|
520
|
+
values.kind !== undefined ||
|
|
521
|
+
values.query !== undefined ||
|
|
522
|
+
values.limit !== undefined ||
|
|
523
|
+
values['max-bytes'] !== undefined ||
|
|
524
|
+
values.rebuild === true ||
|
|
525
|
+
values.host !== undefined ||
|
|
526
|
+
hasContinuityOptions(values)) {
|
|
527
|
+
failure(output, json, 'invalid_arguments', 'mcp accepts only --root, --help, and --json.');
|
|
528
|
+
return 2;
|
|
529
|
+
}
|
|
530
|
+
if (values.help) {
|
|
531
|
+
if (json) {
|
|
532
|
+
output.stdout(`${JSON.stringify({ ...info, commands: ['mcp'], usage: mcpUsage })}\n`);
|
|
533
|
+
}
|
|
534
|
+
else {
|
|
535
|
+
output.stdout(mcpUsage);
|
|
536
|
+
}
|
|
537
|
+
return 0;
|
|
538
|
+
}
|
|
539
|
+
if (values.version) {
|
|
540
|
+
failure(output, json, 'invalid_arguments', '--version cannot be combined with mcp.');
|
|
541
|
+
return 2;
|
|
542
|
+
}
|
|
543
|
+
return runMcpCommand({ cwd: process.cwd(), root: values.root ?? null, json }, output);
|
|
544
|
+
}
|
|
419
545
|
if (command === 'onboard') {
|
|
420
546
|
if (values.apply === true ||
|
|
421
547
|
values['install-runtime'] === true ||
|
|
@@ -723,6 +849,8 @@ export async function runCli(args, output) {
|
|
|
723
849
|
'install',
|
|
724
850
|
'verify',
|
|
725
851
|
'bundle',
|
|
852
|
+
'mcp',
|
|
853
|
+
'probe',
|
|
726
854
|
];
|
|
727
855
|
const action = allowedActions.find((item) => item === hostAction) ?? null;
|
|
728
856
|
const parsedHost = hostNameSchema.safeParse(values.host);
|
|
@@ -742,7 +870,7 @@ export async function runCli(args, output) {
|
|
|
742
870
|
values['max-bytes'] !== undefined ||
|
|
743
871
|
values.rebuild === true ||
|
|
744
872
|
hasContinuityOptions(values) ||
|
|
745
|
-
(values.apply === true && action !== 'install') ||
|
|
873
|
+
(values.apply === true && action !== 'install' && action !== 'mcp') ||
|
|
746
874
|
(values.mode !== undefined && action !== 'install') ||
|
|
747
875
|
(values.marketplace === true && action !== 'bundle') ||
|
|
748
876
|
(values.scope !== undefined &&
|
|
@@ -772,6 +900,8 @@ export async function runCli(args, output) {
|
|
|
772
900
|
hostRoot: values['host-root'] ?? null,
|
|
773
901
|
hostVersion: values['host-version'] ?? null,
|
|
774
902
|
apply: values.apply === true,
|
|
903
|
+
force: values.force === true,
|
|
904
|
+
subAction: hostSubAction ?? null,
|
|
775
905
|
out: values.out ?? null,
|
|
776
906
|
mode: values.mode === 'project-settings' || values.mode === 'plugin'
|
|
777
907
|
? values.mode
|
|
@@ -10,6 +10,7 @@ import { resolveWorkspaceRoot } from '../../workspace/resolve.js';
|
|
|
10
10
|
import { inspectMachineConfig, loadWorkspaceConfig, } from '../../workspace/config.js';
|
|
11
11
|
import { CheckpointService } from '../../continuity/service.js';
|
|
12
12
|
import { ensureStatePathBoundary } from '../../install/ownership.js';
|
|
13
|
+
import { readAutoResume, readTaskPin } from '../../app/task-pin.js';
|
|
13
14
|
import { nativeEventFor } from './support.js';
|
|
14
15
|
const DEFAULT_MAX_INPUT_BYTES = 1024 * 1024;
|
|
15
16
|
const DEFAULT_DEADLINE_MS = 1000;
|
|
@@ -489,7 +490,9 @@ export async function runHostHook(input, options = {}) {
|
|
|
489
490
|
dev: directoryAfter.stats.dev,
|
|
490
491
|
ino: directoryAfter.stats.ino,
|
|
491
492
|
};
|
|
492
|
-
const
|
|
493
|
+
const pinnedTask = await readTaskPin(root);
|
|
494
|
+
const autoResume = pinnedTask !== null && (await readAutoResume(root));
|
|
495
|
+
const context = await boundedAdvisory(root, value.event, value.taskId ?? (autoResume ? pinnedTask.taskId : null), workspaceRead.value.name);
|
|
493
496
|
if (clock() - started > deadline) {
|
|
494
497
|
return result({
|
|
495
498
|
ok: false,
|
|
@@ -6,8 +6,8 @@ var __export = (target, all) => {
|
|
|
6
6
|
|
|
7
7
|
// dist/hosts/integration/hook.js
|
|
8
8
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
9
|
-
import { link as link2, mkdir as
|
|
10
|
-
import { isAbsolute as isAbsolute4, join as
|
|
9
|
+
import { link as link2, mkdir as mkdir4, open as open5, rm as rm2 } from "node:fs/promises";
|
|
10
|
+
import { isAbsolute as isAbsolute4, join as join9, relative as relative3, resolve as resolve6, sep as sep3 } from "node:path";
|
|
11
11
|
|
|
12
12
|
// dist/schemas/diagnostics.js
|
|
13
13
|
function createDiagnostic(input2) {
|
|
@@ -20662,6 +20662,9 @@ var workspaceValidationSchema = external_exports.strictObject({
|
|
|
20662
20662
|
executable: executableSchema,
|
|
20663
20663
|
args: external_exports.array(argumentSchema).max(256)
|
|
20664
20664
|
});
|
|
20665
|
+
var workspaceContinuitySchema = external_exports.strictObject({
|
|
20666
|
+
autoResume: external_exports.boolean()
|
|
20667
|
+
});
|
|
20665
20668
|
var workspaceConfigSchema = external_exports.strictObject({
|
|
20666
20669
|
schema: external_exports.literal(WORKSPACE_SCHEMA),
|
|
20667
20670
|
workspaceId: external_exports.uuid(),
|
|
@@ -20672,7 +20675,8 @@ var workspaceConfigSchema = external_exports.strictObject({
|
|
|
20672
20675
|
code: workspaceCodeSchema,
|
|
20673
20676
|
validation: external_exports.array(workspaceValidationSchema).max(128),
|
|
20674
20677
|
excludes: external_exports.array(portablePathSchema).max(128),
|
|
20675
|
-
extensions: external_exports.record(external_exports.string().min(1).max(128), external_exports.unknown())
|
|
20678
|
+
extensions: external_exports.record(external_exports.string().min(1).max(128), external_exports.unknown()),
|
|
20679
|
+
continuity: workspaceContinuitySchema.optional()
|
|
20676
20680
|
});
|
|
20677
20681
|
function pathDiagnostic(value, source, fieldPointer, label) {
|
|
20678
20682
|
const hint = 'Use a workspace-relative path such as "docs" or "repos/app".';
|
|
@@ -23928,6 +23932,42 @@ async function ensureStatePathBoundary(root, path) {
|
|
|
23928
23932
|
}
|
|
23929
23933
|
}
|
|
23930
23934
|
|
|
23935
|
+
// dist/app/task-pin.js
|
|
23936
|
+
import { mkdir as mkdir3, readFile, rename as rename2, writeFile } from "node:fs/promises";
|
|
23937
|
+
import { dirname as dirname5, join as join8 } from "node:path";
|
|
23938
|
+
var TASK_PIN_SCHEMA = "pappra/task-pin/1";
|
|
23939
|
+
var TASK_ID2 = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
23940
|
+
function pinPath(root) {
|
|
23941
|
+
return join8(root, ".pappra", "local", "current-task");
|
|
23942
|
+
}
|
|
23943
|
+
async function readTaskPin(root) {
|
|
23944
|
+
const read = await readTextFileBounded(pinPath(root), 64 * 1024);
|
|
23945
|
+
if (!read.ok)
|
|
23946
|
+
return null;
|
|
23947
|
+
try {
|
|
23948
|
+
const value = JSON.parse(read.value.text);
|
|
23949
|
+
if (typeof value !== "object" || value === null || !("schema" in value) || value.schema !== TASK_PIN_SCHEMA || !("taskId" in value) || typeof value.taskId !== "string" || !TASK_ID2.test(value.taskId)) {
|
|
23950
|
+
return null;
|
|
23951
|
+
}
|
|
23952
|
+
return value;
|
|
23953
|
+
} catch {
|
|
23954
|
+
return null;
|
|
23955
|
+
}
|
|
23956
|
+
}
|
|
23957
|
+
async function readAutoResume(root) {
|
|
23958
|
+
const read = await readFile(join8(root, ".pappra", "workspace.json"), "utf8");
|
|
23959
|
+
try {
|
|
23960
|
+
const raw = JSON.parse(read);
|
|
23961
|
+
if (typeof raw !== "object" || raw === null || !("continuity" in raw)) {
|
|
23962
|
+
return false;
|
|
23963
|
+
}
|
|
23964
|
+
const continuity = raw.continuity;
|
|
23965
|
+
return typeof continuity === "object" && continuity !== null && "autoResume" in continuity && continuity.autoResume === true;
|
|
23966
|
+
} catch {
|
|
23967
|
+
return false;
|
|
23968
|
+
}
|
|
23969
|
+
}
|
|
23970
|
+
|
|
23931
23971
|
// dist/hosts/integration/support.js
|
|
23932
23972
|
var HOST_SUPPORT = {
|
|
23933
23973
|
pi: {
|
|
@@ -24015,7 +24055,7 @@ async function privateSegmentsSafe(root, directory) {
|
|
|
24015
24055
|
}
|
|
24016
24056
|
let current = root;
|
|
24017
24057
|
for (const segment of rel.split(sep3)) {
|
|
24018
|
-
current =
|
|
24058
|
+
current = join9(current, segment);
|
|
24019
24059
|
const observed = await observePath(current);
|
|
24020
24060
|
if (observed.kind === "missing")
|
|
24021
24061
|
return true;
|
|
@@ -24256,7 +24296,7 @@ async function runHostHook(input2, options = {}) {
|
|
|
24256
24296
|
});
|
|
24257
24297
|
}
|
|
24258
24298
|
const eventKey = value.eventId === null ? null : sha256Digest([value.host, value.event, value.sessionId ?? "", value.eventId].join("\0"));
|
|
24259
|
-
const directory =
|
|
24299
|
+
const directory = join9(root, ".pappra", "local", "host-events", value.host);
|
|
24260
24300
|
if (!await privateSegmentsSafe(root, directory)) {
|
|
24261
24301
|
return result2({
|
|
24262
24302
|
ok: false,
|
|
@@ -24301,7 +24341,7 @@ async function runHostHook(input2, options = {}) {
|
|
|
24301
24341
|
]
|
|
24302
24342
|
});
|
|
24303
24343
|
}
|
|
24304
|
-
await
|
|
24344
|
+
await mkdir4(directory, { recursive: true, mode: 448 });
|
|
24305
24345
|
const directoryAfter = await observePath(directory);
|
|
24306
24346
|
const realDirectory = await resolveRealpath(directory);
|
|
24307
24347
|
const privateAfter = await privateSegmentsSafe(root, directory);
|
|
@@ -24326,7 +24366,9 @@ async function runHostHook(input2, options = {}) {
|
|
|
24326
24366
|
dev: directoryAfter.stats.dev,
|
|
24327
24367
|
ino: directoryAfter.stats.ino
|
|
24328
24368
|
};
|
|
24329
|
-
const
|
|
24369
|
+
const pinnedTask = await readTaskPin(root);
|
|
24370
|
+
const autoResume = pinnedTask !== null && await readAutoResume(root);
|
|
24371
|
+
const context = await boundedAdvisory(root, value.event, value.taskId ?? (autoResume ? pinnedTask.taskId : null), workspaceRead.value.name);
|
|
24330
24372
|
if (clock() - started > deadline) {
|
|
24331
24373
|
return result2({
|
|
24332
24374
|
ok: false,
|
|
@@ -24342,7 +24384,7 @@ async function runHostHook(input2, options = {}) {
|
|
|
24342
24384
|
});
|
|
24343
24385
|
}
|
|
24344
24386
|
const fileName = eventKey === null ? `${sha256Digest(`${value.observedAt}\0${randomUUID3()}`).slice(7)}.json` : `${eventKey.slice(7)}.json`;
|
|
24345
|
-
const path =
|
|
24387
|
+
const path = join9(directory, fileName);
|
|
24346
24388
|
const record2 = Buffer.from(`${JSON.stringify({
|
|
24347
24389
|
schema: "pappra/host-event/1",
|
|
24348
24390
|
host: value.host,
|
|
@@ -6,8 +6,8 @@ var __export = (target, all) => {
|
|
|
6
6
|
|
|
7
7
|
// dist/hosts/integration/hook.js
|
|
8
8
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
9
|
-
import { link as link2, mkdir as
|
|
10
|
-
import { isAbsolute as isAbsolute4, join as
|
|
9
|
+
import { link as link2, mkdir as mkdir4, open as open5, rm as rm2 } from "node:fs/promises";
|
|
10
|
+
import { isAbsolute as isAbsolute4, join as join9, relative as relative3, resolve as resolve6, sep as sep3 } from "node:path";
|
|
11
11
|
|
|
12
12
|
// dist/schemas/diagnostics.js
|
|
13
13
|
function createDiagnostic(input2) {
|
|
@@ -20667,6 +20667,9 @@ var workspaceValidationSchema = external_exports.strictObject({
|
|
|
20667
20667
|
executable: executableSchema,
|
|
20668
20668
|
args: external_exports.array(argumentSchema).max(256)
|
|
20669
20669
|
});
|
|
20670
|
+
var workspaceContinuitySchema = external_exports.strictObject({
|
|
20671
|
+
autoResume: external_exports.boolean()
|
|
20672
|
+
});
|
|
20670
20673
|
var workspaceConfigSchema = external_exports.strictObject({
|
|
20671
20674
|
schema: external_exports.literal(WORKSPACE_SCHEMA),
|
|
20672
20675
|
workspaceId: external_exports.uuid(),
|
|
@@ -20677,7 +20680,8 @@ var workspaceConfigSchema = external_exports.strictObject({
|
|
|
20677
20680
|
code: workspaceCodeSchema,
|
|
20678
20681
|
validation: external_exports.array(workspaceValidationSchema).max(128),
|
|
20679
20682
|
excludes: external_exports.array(portablePathSchema).max(128),
|
|
20680
|
-
extensions: external_exports.record(external_exports.string().min(1).max(128), external_exports.unknown())
|
|
20683
|
+
extensions: external_exports.record(external_exports.string().min(1).max(128), external_exports.unknown()),
|
|
20684
|
+
continuity: workspaceContinuitySchema.optional()
|
|
20681
20685
|
});
|
|
20682
20686
|
function pathDiagnostic(value, source, fieldPointer, label) {
|
|
20683
20687
|
const hint = 'Use a workspace-relative path such as "docs" or "repos/app".';
|
|
@@ -23933,6 +23937,42 @@ async function ensureStatePathBoundary(root, path) {
|
|
|
23933
23937
|
}
|
|
23934
23938
|
}
|
|
23935
23939
|
|
|
23940
|
+
// dist/app/task-pin.js
|
|
23941
|
+
import { mkdir as mkdir3, readFile, rename as rename2, writeFile } from "node:fs/promises";
|
|
23942
|
+
import { dirname as dirname5, join as join8 } from "node:path";
|
|
23943
|
+
var TASK_PIN_SCHEMA = "pappra/task-pin/1";
|
|
23944
|
+
var TASK_ID2 = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
23945
|
+
function pinPath(root) {
|
|
23946
|
+
return join8(root, ".pappra", "local", "current-task");
|
|
23947
|
+
}
|
|
23948
|
+
async function readTaskPin(root) {
|
|
23949
|
+
const read = await readTextFileBounded(pinPath(root), 64 * 1024);
|
|
23950
|
+
if (!read.ok)
|
|
23951
|
+
return null;
|
|
23952
|
+
try {
|
|
23953
|
+
const value = JSON.parse(read.value.text);
|
|
23954
|
+
if (typeof value !== "object" || value === null || !("schema" in value) || value.schema !== TASK_PIN_SCHEMA || !("taskId" in value) || typeof value.taskId !== "string" || !TASK_ID2.test(value.taskId)) {
|
|
23955
|
+
return null;
|
|
23956
|
+
}
|
|
23957
|
+
return value;
|
|
23958
|
+
} catch {
|
|
23959
|
+
return null;
|
|
23960
|
+
}
|
|
23961
|
+
}
|
|
23962
|
+
async function readAutoResume(root) {
|
|
23963
|
+
const read = await readFile(join8(root, ".pappra", "workspace.json"), "utf8");
|
|
23964
|
+
try {
|
|
23965
|
+
const raw = JSON.parse(read);
|
|
23966
|
+
if (typeof raw !== "object" || raw === null || !("continuity" in raw)) {
|
|
23967
|
+
return false;
|
|
23968
|
+
}
|
|
23969
|
+
const continuity = raw.continuity;
|
|
23970
|
+
return typeof continuity === "object" && continuity !== null && "autoResume" in continuity && continuity.autoResume === true;
|
|
23971
|
+
} catch {
|
|
23972
|
+
return false;
|
|
23973
|
+
}
|
|
23974
|
+
}
|
|
23975
|
+
|
|
23936
23976
|
// dist/hosts/integration/support.js
|
|
23937
23977
|
var HOST_SUPPORT = {
|
|
23938
23978
|
pi: {
|
|
@@ -24038,7 +24078,7 @@ async function privateSegmentsSafe(root, directory) {
|
|
|
24038
24078
|
}
|
|
24039
24079
|
let current = root;
|
|
24040
24080
|
for (const segment of rel.split(sep3)) {
|
|
24041
|
-
current =
|
|
24081
|
+
current = join9(current, segment);
|
|
24042
24082
|
const observed = await observePath(current);
|
|
24043
24083
|
if (observed.kind === "missing")
|
|
24044
24084
|
return true;
|
|
@@ -24337,7 +24377,7 @@ async function runHostHook(input2, options = {}) {
|
|
|
24337
24377
|
});
|
|
24338
24378
|
}
|
|
24339
24379
|
const eventKey = value.eventId === null ? null : sha256Digest([value.host, value.event, value.sessionId ?? "", value.eventId].join("\0"));
|
|
24340
|
-
const directory =
|
|
24380
|
+
const directory = join9(root, ".pappra", "local", "host-events", value.host);
|
|
24341
24381
|
if (!await privateSegmentsSafe(root, directory)) {
|
|
24342
24382
|
return result2({
|
|
24343
24383
|
ok: false,
|
|
@@ -24382,7 +24422,7 @@ async function runHostHook(input2, options = {}) {
|
|
|
24382
24422
|
]
|
|
24383
24423
|
});
|
|
24384
24424
|
}
|
|
24385
|
-
await
|
|
24425
|
+
await mkdir4(directory, { recursive: true, mode: 448 });
|
|
24386
24426
|
const directoryAfter = await observePath(directory);
|
|
24387
24427
|
const realDirectory = await resolveRealpath(directory);
|
|
24388
24428
|
const privateAfter = await privateSegmentsSafe(root, directory);
|
|
@@ -24407,7 +24447,9 @@ async function runHostHook(input2, options = {}) {
|
|
|
24407
24447
|
dev: directoryAfter.stats.dev,
|
|
24408
24448
|
ino: directoryAfter.stats.ino
|
|
24409
24449
|
};
|
|
24410
|
-
const
|
|
24450
|
+
const pinnedTask = await readTaskPin(root);
|
|
24451
|
+
const autoResume = pinnedTask !== null && await readAutoResume(root);
|
|
24452
|
+
const context = await boundedAdvisory(root, value.event, value.taskId ?? (autoResume ? pinnedTask.taskId : null), workspaceRead.value.name);
|
|
24411
24453
|
if (clock() - started > deadline) {
|
|
24412
24454
|
return result2({
|
|
24413
24455
|
ok: false,
|
|
@@ -24423,7 +24465,7 @@ async function runHostHook(input2, options = {}) {
|
|
|
24423
24465
|
});
|
|
24424
24466
|
}
|
|
24425
24467
|
const fileName = eventKey === null ? `${sha256Digest(`${value.observedAt}\0${randomUUID3()}`).slice(7)}.json` : `${eventKey.slice(7)}.json`;
|
|
24426
|
-
const path =
|
|
24468
|
+
const path = join9(directory, fileName);
|
|
24427
24469
|
const record2 = Buffer.from(`${JSON.stringify({
|
|
24428
24470
|
schema: "pappra/host-event/1",
|
|
24429
24471
|
host: value.host,
|