@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/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 > 2) {
132
- throw new Error('host accepts one action: detect, describe, plan, install, or verify.');
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 context = await boundedAdvisory(root, value.event, value.taskId, workspaceRead.value.name);
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 mkdir3, open as open5, rm as rm2 } from "node:fs/promises";
10
- import { isAbsolute as isAbsolute4, join as join8, relative as relative3, resolve as resolve6, sep as sep3 } from "node:path";
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 = join8(current, segment);
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 = join8(root, ".pappra", "local", "host-events", value.host);
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 mkdir3(directory, { recursive: true, mode: 448 });
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 context = await boundedAdvisory(root, value.event, value.taskId, workspaceRead.value.name);
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 = join8(directory, fileName);
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 mkdir3, open as open5, rm as rm2 } from "node:fs/promises";
10
- import { isAbsolute as isAbsolute4, join as join8, relative as relative3, resolve as resolve6, sep as sep3 } from "node:path";
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 = join8(current, segment);
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 = join8(root, ".pappra", "local", "host-events", value.host);
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 mkdir3(directory, { recursive: true, mode: 448 });
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 context = await boundedAdvisory(root, value.event, value.taskId, workspaceRead.value.name);
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 = join8(directory, fileName);
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,