@phyzess/pappra 0.1.0-beta.10 → 0.1.0-beta.11

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 CHANGED
@@ -64,7 +64,7 @@ They are not needed for the core workflow above.
64
64
  - **Workspace configuration:** `.pappra/workspace.json` and checkout-local `.pappra/local/machine.json`.
65
65
  - **Knowledge:** workspace and private document catalogs with explicit preview/apply operations.
66
66
  - **Continuity:** private task checkpoints and bounded advisory resume packets. Resume never grants execution by itself.
67
- - **Code intelligence:** status, explicit preparation and bounded query for selected repositories. Text/structure fallback is available when the optional graph engine is absent.
67
+ - **Code intelligence:** status, explicit preparation and bounded query for selected repositories. Text/structure fallback is available when the optional graph engine is absent. Registrations are stored under the workspace `.pappra/local/code`, never inside a repository checkout, so a multi-repository workspace does not turn its checkouts into nested workspaces.
68
68
  - **Host integrations:** optional Pi, Codex and Claude Code adapters that merge Pappra-owned entries without taking over user configuration. Hooks are copied as a dependency-free bundle; Claude Code uses `${CLAUDE_PROJECT_DIR}` and Pi imports its runtime relatively, while Codex 0.163.0 loads hooks only from `$CODEX_HOME/hooks.json` (`host install --host codex --scope user`). `host bundle --marketplace` exports a marketplace that Claude Code and Codex accept without registering it. Plugin hooks are verified for Pi 1.3.0 and Claude Code 2.1.292 (startup) and unsupported for Codex, so `host install --mode plugin` fails closed with the per-host registration commands. See [host plugin validation](docs/host-plugin-validation.md).
69
69
  - **Bounded collaboration:** an optional, explicitly controlled one-request workflow. It is not a scheduler or daemon.
70
70
 
@@ -89,7 +89,7 @@ The check runs the source policy, type checks, formatting, deterministic tests a
89
89
 
90
90
  ## Status and limits
91
91
 
92
- Pappra is development software (`0.1.0-beta.10`) published as `@phyzess/pappra` under the `beta` dist-tag. Releases are published from GitHub Actions with npm trusted publishing (OIDC), so no npm token is stored in this repository. Pin either the moving `beta` tag or an exact version such as `@phyzess/pappra@0.1.0-beta.10`, because pre-release versions are never republished.
92
+ Pappra is development software (`0.1.0-beta.11`) published as `@phyzess/pappra` under the `beta` dist-tag. Releases are published from GitHub Actions with npm trusted publishing (OIDC), so no npm token is stored in this repository. Pin either the moving `beta` tag or an exact version such as `@phyzess/pappra@0.1.0-beta.11`, because pre-release versions are never republished.
93
93
 
94
94
  The deterministic suite covers synthetic workspaces, fixtures and local process boundaries. It does not establish real-model behavior, native host callability on every platform, CodeGraph completeness, Windows/Linux parity or production performance. A host adapter version pin is an observed support claim, not proof that a particular native installation will load or run correctly.
95
95
 
@@ -886,14 +886,33 @@ export async function runDoctor(options = {}) {
886
886
  ],
887
887
  }));
888
888
  const selectedHosts = machine?.selectedHosts ?? [];
889
- const hostRootBase = root ?? homeDir;
889
+ // Passive observation only: a host install can target the private default root, a
890
+ // project directory, or Codex's user configuration directory.
891
+ const hostInstallRoots = (host) => {
892
+ const roots = [
893
+ join(root ?? homeDir, '.pappra', 'local', 'hosts', host),
894
+ join(root ?? homeDir, `.${host}`),
895
+ ];
896
+ if (host === 'codex') {
897
+ roots.push(process.env['CODEX_HOME'] ?? join(homeDir, '.codex'));
898
+ }
899
+ return roots;
900
+ };
890
901
  const installedHostBundle = (await Promise.all(selectedHosts.map(async (host) => {
891
- const path = join(hostRootBase, '.pappra', 'local', 'hosts', host, 'pappra-host.json');
892
- return (await observePath(path)).kind === 'file' ? path : null;
902
+ for (const base of hostInstallRoots(host)) {
903
+ const path = join(base, 'pappra-host.json');
904
+ if ((await observePath(path)).kind === 'file')
905
+ return path;
906
+ }
907
+ return null;
893
908
  }))).find((path) => path !== null) ?? null;
894
909
  const installedHostSkill = (await Promise.all(selectedHosts.map(async (host) => {
895
- const path = join(hostRootBase, '.pappra', 'local', 'hosts', host, 'skills', 'pappra', 'SKILL.md');
896
- return (await observePath(path)).kind === 'file' ? path : null;
910
+ for (const base of hostInstallRoots(host)) {
911
+ const path = join(base, 'skills', 'pappra', 'SKILL.md');
912
+ if ((await observePath(path)).kind === 'file')
913
+ return path;
914
+ }
915
+ return null;
897
916
  }))).find((path) => path !== null) ?? null;
898
917
  checks.push(...hostChecks(selectedHosts, homeDir, pathEnv, observedAt));
899
918
  checks.push(makeCheck({
@@ -177,7 +177,10 @@ async function observeCode(input) {
177
177
  : fallbackHealth('unsupported', raw.code, versionValue);
178
178
  if (!raw.ok)
179
179
  diagnostics.push(outcomeDiagnostic(raw, repository.root));
180
- const registrationRead = await readCodeRegistration(repository.root, input.repositoryId);
180
+ // Registrations belong to the workspace, not to a repository checkout: writing
181
+ // <repo>/.pappra/local/code would make that checkout look like a nested workspace
182
+ // and hide it from the outer workspace discovery.
183
+ const registrationRead = await readCodeRegistration(input.root, input.repositoryId);
181
184
  let registration = null;
182
185
  let registrationFailure = null;
183
186
  if (registrationRead.ok) {
@@ -193,7 +196,7 @@ async function observeCode(input) {
193
196
  rawHealth,
194
197
  health,
195
198
  registration,
196
- registrationPath: codeRegistrationPath(repository.root, input.repositoryId),
199
+ registrationPath: codeRegistrationPath(input.root, input.repositoryId),
197
200
  excludedRoots,
198
201
  access: repository.access,
199
202
  diagnostics,
@@ -345,9 +348,12 @@ export class CodeIntelligenceService {
345
348
  diagnostics: [...observed.diagnostics],
346
349
  };
347
350
  }
348
- const registrationTarget = codeRegistrationPath(observed.identity.root, observed.identity.repositoryId);
349
- for (const target of [plan.indexPath, registrationTarget]) {
350
- const boundary = await ensureCodeMutationBoundary(observed.identity.root, target, observed.excludedRoots);
351
+ const registrationTarget = codeRegistrationPath(input.root, observed.identity.repositoryId);
352
+ const boundaries = await Promise.all([
353
+ ensureCodeMutationBoundary(observed.identity.root, plan.indexPath, observed.excludedRoots),
354
+ ensureCodeMutationBoundary(input.root, registrationTarget),
355
+ ]);
356
+ for (const boundary of boundaries) {
351
357
  if (!boundary.ok) {
352
358
  return {
353
359
  schema: 'pappra/code-prepare-result/1',
@@ -364,12 +370,12 @@ export class CodeIntelligenceService {
364
370
  registrationPath: null,
365
371
  diagnostics: [
366
372
  ...observed.diagnostics,
367
- outcomeDiagnostic(boundary, target),
373
+ outcomeDiagnostic(boundary, registrationTarget),
368
374
  ],
369
375
  };
370
376
  }
371
377
  }
372
- const lock = await acquireCodePrepareLock(observed.identity.root, observed.excludedRoots);
378
+ const lock = await acquireCodePrepareLock(input.root);
373
379
  if (!lock.ok) {
374
380
  return {
375
381
  schema: 'pappra/code-prepare-result/1',
@@ -507,7 +513,7 @@ export class CodeIntelligenceService {
507
513
  preparedAt: new Date().toISOString(),
508
514
  coverage: prepared.value.coverage,
509
515
  };
510
- const written = await writeCodeRegistration(afterIdentity.value.root, registration, observed.excludedRoots);
516
+ const written = await writeCodeRegistration(input.root, registration);
511
517
  if (!written.ok) {
512
518
  return {
513
519
  schema: 'pappra/code-prepare-result/1',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phyzess/pappra",
3
- "version": "0.1.0-beta.10",
3
+ "version": "0.1.0-beta.11",
4
4
  "description": "Portable workspace knowledge and continuity for coding agents.",
5
5
  "publishConfig": {
6
6
  "access": "public"