forge-workflow 0.1.0-beta.5 → 0.1.0-beta.6

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.
Files changed (128) hide show
  1. package/AGENTS.md +4 -0
  2. package/CHANGELOG.md +36 -0
  3. package/CLAUDE.md +0 -12
  4. package/CODING_STANDARDS.md +72 -0
  5. package/bin/forge.js +12 -1
  6. package/docs/guides/MIGRATION.md +3 -3
  7. package/docs/reference/FORGE_KERNEL_STORAGE_MODEL.md +4 -0
  8. package/docs/reference/INSTALL.md +4 -0
  9. package/docs/reference/LEGACY_CLAIM_REPAIR.md +112 -0
  10. package/docs/reference/RELEASE.md +4 -4
  11. package/docs/reference/github-accounts.md +134 -0
  12. package/docs/reference/shepherd.md +63 -13
  13. package/lib/adapters/pr-state-adapter.js +15 -2
  14. package/lib/base-remote.js +138 -0
  15. package/lib/beta5-compatibility-evidence.js +1093 -0
  16. package/lib/bun-lockfile-proof.js +413 -0
  17. package/lib/bun-workflow-pins.js +461 -0
  18. package/lib/capabilities/index.js +9 -0
  19. package/lib/capabilities/model.js +141 -0
  20. package/lib/capabilities/probes.js +347 -0
  21. package/lib/codex-skills.js +2 -2
  22. package/lib/commands/_manifest.js +1 -0
  23. package/lib/commands/_registry.js +48 -18
  24. package/lib/commands/clean.js +57 -1
  25. package/lib/commands/doctor.js +37 -6
  26. package/lib/commands/gate.js +197 -27
  27. package/lib/commands/github.js +215 -0
  28. package/lib/commands/hooks.js +54 -6
  29. package/lib/commands/memory.js +66 -2
  30. package/lib/commands/merge.js +720 -73
  31. package/lib/commands/plan.js +33 -2
  32. package/lib/commands/pr.js +2 -0
  33. package/lib/commands/preflight.js +10 -2
  34. package/lib/commands/push.js +108 -6
  35. package/lib/commands/recall.js +95 -61
  36. package/lib/commands/release.js +23 -2
  37. package/lib/commands/remember.js +28 -4
  38. package/lib/commands/serve.js +26 -9
  39. package/lib/commands/setup.js +132 -4
  40. package/lib/commands/shepherd.js +578 -72
  41. package/lib/commands/ship.js +15 -69
  42. package/lib/commands/skill.js +8 -0
  43. package/lib/commands/team.js +47 -8
  44. package/lib/commands/test.js +163 -4
  45. package/lib/commands/validate.js +65 -21
  46. package/lib/commands/worktree.js +155 -19
  47. package/lib/fixtures/beta5-corpus/v1/README.md +9 -0
  48. package/lib/fixtures/beta5-corpus/v1/contract/command-contract.json +26 -0
  49. package/lib/fixtures/beta5-corpus/v1/contract/package-contract.json +13 -0
  50. package/lib/fixtures/beta5-corpus/v1/contract/workflow-stage-matrix.json +8 -0
  51. package/lib/fixtures/beta5-corpus/v1/manifest.json +25 -0
  52. package/lib/fixtures/beta5-corpus/v1/state/comments.jsonl +1 -0
  53. package/lib/fixtures/beta5-corpus/v1/state/config.yaml +6 -0
  54. package/lib/fixtures/beta5-corpus/v1/state/dependencies.jsonl +1 -0
  55. package/lib/fixtures/beta5-corpus/v1/state/issues.jsonl +2 -0
  56. package/lib/fixtures/beta5-corpus/v1/state/kernel.sql +20 -0
  57. package/lib/forge-issues.js +78 -0
  58. package/lib/gate-events.js +98 -10
  59. package/lib/github-context.js +308 -0
  60. package/lib/global-flags.js +1 -0
  61. package/lib/hook-renderer.js +29 -1
  62. package/lib/issue-render.js +19 -0
  63. package/lib/kernel/broker.js +723 -31
  64. package/lib/kernel/claim-reconciler.js +238 -0
  65. package/lib/kernel/lease-enforcer.js +9 -4
  66. package/lib/kernel/legacy-claim-repair.js +442 -0
  67. package/lib/kernel/live-claim-projection.js +26 -0
  68. package/lib/kernel/migrations.js +118 -3
  69. package/lib/kernel/readiness-model.js +184 -12
  70. package/lib/kernel/schema.js +49 -1
  71. package/lib/kernel/sqlite-driver.js +3322 -183
  72. package/lib/kernel/taxonomy-validator.js +4 -1
  73. package/lib/kernel/windows-private-acl.js +239 -0
  74. package/lib/memory/hygiene.js +191 -0
  75. package/lib/memory/router.js +94 -27
  76. package/lib/memory/usage-evidence.js +4 -0
  77. package/lib/memory-digest.js +59 -0
  78. package/lib/merge-rules.js +135 -17
  79. package/lib/npm-publish-workflow.js +233 -40
  80. package/lib/package-root.js +2 -0
  81. package/lib/pr-monitor/auto-actions.js +169 -28
  82. package/lib/pr-monitor/differ.js +110 -4
  83. package/lib/pr-monitor/events.js +0 -0
  84. package/lib/pr-monitor/flow-monitor.js +1424 -0
  85. package/lib/pr-monitor/gather.js +251 -44
  86. package/lib/pr-monitor/journal.js +0 -37
  87. package/lib/pr-monitor/monitor.js +117 -10
  88. package/lib/pr-monitor/process-identity.js +117 -0
  89. package/lib/pr-monitor/reconcile-executor.js +1101 -625
  90. package/lib/pr-monitor/reconcile.js +0 -0
  91. package/lib/pr-monitor/render-summary.js +121 -24
  92. package/lib/pr-monitor/review-preflight.js +269 -0
  93. package/lib/pr-monitor/shepherd-lease.js +28 -19
  94. package/lib/pr-monitor/verdict.js +438 -0
  95. package/lib/pr-monitor/watch-lifecycle.js +144 -38
  96. package/lib/pr-monitor/watch-owner.js +1414 -0
  97. package/lib/pr-monitor/watch.js +129 -58
  98. package/lib/pr-shepherd.js +17 -3
  99. package/lib/project-memory.js +145 -3
  100. package/lib/protected-state-authority.js +799 -4
  101. package/lib/protected-state-surfaces.js +181 -3
  102. package/lib/release-readiness.js +2 -3
  103. package/lib/review-adapter.js +65 -0
  104. package/lib/skills-sync.js +65 -32
  105. package/lib/validation/risk-manifest.js +339 -0
  106. package/lib/workflow/enforce-stage.js +44 -0
  107. package/lib/workflow/plan-authority.js +225 -0
  108. package/package.json +8 -4
  109. package/scripts/commitlint.js +13 -15
  110. package/scripts/generate-risk-manifest.js +91 -0
  111. package/scripts/github-context-bridge.sh +10 -0
  112. package/scripts/legacy-claim-repair.js +145 -0
  113. package/scripts/lib/behavioral-eval-runtime.js +3 -2
  114. package/scripts/process-tree.js +14 -2
  115. package/scripts/protected-state-check.js +440 -17
  116. package/scripts/sync-agent-skills.js +333 -34
  117. package/scripts/test-full-suite.js +704 -18
  118. package/scripts/test-profile.js +13 -3
  119. package/scripts/test.js +95 -14
  120. package/skills/coverage.json +1 -0
  121. package/skills/review/SKILL.md +2 -0
  122. package/skills/review/evals/scorecard.json +2 -2
  123. package/skills/setup/SKILL.md +18 -0
  124. package/skills/setup/evals/scorecard.json +3 -3
  125. package/skills/shepherd/SKILL.md +19 -2
  126. package/skills/shepherd/evals/scorecard.json +3 -3
  127. package/skills/validate/SKILL.md +3 -0
  128. package/skills/validate/evals/scorecard.json +1 -1
@@ -1,15 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * Cross-platform commitlint runner for lefthook commit-msg hook.
4
- * Replaces direct npx invocation which fails on Windows without shell: true.
5
- * Works on Windows CMD, PowerShell, macOS, Linux.
4
+ * Executes the installed commitlint CLI directly on Windows, macOS, and Linux.
6
5
  */
7
6
 
8
7
  const { spawnSync } = require('node:child_process');
9
8
 
10
- // On Windows, npx is npx.cmd — shell: true resolves .cmd extensions
11
- const isWindows = process.platform === 'win32';
12
-
13
9
  const commitMsgFile = process.argv[2];
14
10
  if (!commitMsgFile) {
15
11
  // Write synchronously so the message is flushed before exit: on Windows the
@@ -18,17 +14,19 @@ if (!commitMsgFile) {
18
14
  process.exit(1);
19
15
  }
20
16
 
21
- // Detect package manager: prefer bun (fast, works with bun.lock), fall back to npx
22
- // npx fails on Windows when npm 11's arborist encounters bun.lock instead of package-lock.json
23
- const hasBunLock = require('node:fs').existsSync(
24
- require('node:path').join(__dirname, '../bun.lock')
25
- );
26
- const runner = hasBunLock ? 'bunx' : 'npx';
17
+ let commitlintCli;
18
+ try {
19
+ commitlintCli = require.resolve('@commitlint/cli/cli.js');
20
+ } catch (error) {
21
+ console.error(`❌ Failed to resolve commitlint: ${error.message}`);
22
+ console.error(' Install project dependencies before committing.');
23
+ process.exit(1);
24
+ }
27
25
 
28
26
  const result = spawnSync(
29
- runner,
30
- ['commitlint', '--edit', commitMsgFile],
31
- { stdio: 'inherit', shell: isWindows }
27
+ process.execPath,
28
+ [commitlintCli, '--edit', commitMsgFile],
29
+ { stdio: 'inherit', shell: false }
32
30
  );
33
31
 
34
32
  if (result.error) {
@@ -40,5 +38,5 @@ if (result.error) {
40
38
  }
41
39
 
42
40
  if (result.status !== 0) {
43
- process.exit(result.status);
41
+ process.exit(result.status ?? 1);
44
42
  }
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('node:fs');
5
+ const path = require('node:path');
6
+ const { parse } = require('yaml');
7
+ const { stableStringify } = require('../lib/kernel/evaluators');
8
+ const { hashManifest, validateManifest } = require('../lib/validation/risk-manifest');
9
+ const crypto = require('node:crypto');
10
+
11
+ const ROOT = path.resolve(__dirname, '..');
12
+ const SOURCE_PATH = path.join(ROOT, 'validation', 'risk-manifest.source.yaml');
13
+ const OUTPUT_PATH = path.join(ROOT, 'validation', 'risk-manifest.v1.json');
14
+
15
+ function sha256(value) {
16
+ return `sha256:${crypto.createHash('sha256').update(value, 'utf8').digest('hex')}`;
17
+ }
18
+
19
+ function compareText(left, right) {
20
+ if (left === right) return 0;
21
+ return left < right ? -1 : 1;
22
+ }
23
+
24
+ function sortById(entries) {
25
+ return [...entries].sort((left, right) => compareText(left.id, right.id));
26
+ }
27
+
28
+ function normalizeSource(source) {
29
+ const canonicalSource = source.replaceAll('\r\n', '\n').replaceAll('\r', '\n');
30
+ const parsed = parse(canonicalSource);
31
+ const manifest = {
32
+ schema_id: parsed.schema_id,
33
+ revision: parsed.revision,
34
+ source_hash: sha256(canonicalSource),
35
+ generator_version: 'forge-risk-manifest-generator.v1',
36
+ commands: sortById(parsed.commands).map((command) => ({
37
+ ...command,
38
+ argv: [...command.argv],
39
+ })),
40
+ gates: sortById(parsed.gates).map((gate) => ({
41
+ ...gate,
42
+ command_ids: [...gate.command_ids].sort(compareText),
43
+ })),
44
+ lanes: sortById(parsed.lanes).map((lane) => ({
45
+ ...lane,
46
+ command_ids: [...lane.command_ids].sort(compareText),
47
+ })),
48
+ risks: sortById(parsed.risks).map((risk) => ({
49
+ ...risk,
50
+ gate_ids: [...risk.gate_ids].sort(),
51
+ })),
52
+ owners: sortById(parsed.owners).map((owner) => ({
53
+ ...owner,
54
+ risk_ids: [...owner.risk_ids].sort(),
55
+ canonical_test_ids: [...owner.canonical_test_ids].sort(),
56
+ dependent_routes: [...owner.dependent_routes].sort(),
57
+ platform_runtime_additions: [...owner.platform_runtime_additions].sort(),
58
+ lanes: [...owner.lanes].sort(),
59
+ package_roots: [...owner.package_roots].sort(),
60
+ selectors: [...owner.selectors].sort((left, right) => compareText(left.kind, right.kind)
61
+ || compareText(left.prefix, right.prefix)),
62
+ })),
63
+ unknown_owner_fallback: {
64
+ ...parsed.unknown_owner_fallback,
65
+ required_gates: [...parsed.unknown_owner_fallback.required_gates].sort(),
66
+ },
67
+ };
68
+ manifest.manifest_hash = hashManifest(manifest);
69
+ validateManifest(manifest);
70
+ return JSON.parse(stableStringify(manifest));
71
+ }
72
+
73
+ function generateRiskManifest(source) {
74
+ return `${JSON.stringify(normalizeSource(source), null, 2)}\n`;
75
+ }
76
+
77
+ function main(args = process.argv.slice(2)) {
78
+ const generated = generateRiskManifest(fs.readFileSync(SOURCE_PATH, 'utf8'));
79
+ if (args.includes('--check')) {
80
+ if (!fs.existsSync(OUTPUT_PATH) || fs.readFileSync(OUTPUT_PATH, 'utf8') !== generated) {
81
+ console.error('Risk manifest is stale. Run: node scripts/generate-risk-manifest.js');
82
+ process.exitCode = 1;
83
+ }
84
+ return;
85
+ }
86
+ fs.writeFileSync(OUTPUT_PATH, generated, 'utf8');
87
+ }
88
+
89
+ if (require.main === module) main();
90
+
91
+ module.exports = { generateRiskManifest, normalizeSource };
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env bash
2
+ # GH_CMD bridge: re-enter this Forge runtime without credentials in the Bash parent.
3
+ set -euo pipefail
4
+
5
+ : "${FORGE_GITHUB_RUNTIME:?Forge GitHub runtime is required}"
6
+ if [[ -n "${FORGE_GITHUB_ENTRY:-}" ]]; then
7
+ exec "$FORGE_GITHUB_RUNTIME" "$FORGE_GITHUB_ENTRY" github run -- gh "$@"
8
+ else
9
+ exec "$FORGE_GITHUB_RUNTIME" github run -- gh "$@"
10
+ fi
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const path = require('node:path');
5
+
6
+ const {
7
+ createBuiltinSQLiteDriver,
8
+ hardenBackupPermissions,
9
+ hardenBackupPermissionsBatch,
10
+ } = require('../lib/kernel/sqlite-driver');
11
+ const {
12
+ ClaimRepairError,
13
+ createVerifiedClaimRepairBackup,
14
+ } = require('../lib/kernel/legacy-claim-repair');
15
+
16
+ const HELP = `Usage:
17
+ bun scripts/legacy-claim-repair.js --dry-run --database <kernel.sqlite> --backup <separate.sqlite> --at <canonical-UTC>
18
+ bun scripts/legacy-claim-repair.js --apply --database <kernel.sqlite> --backup <separate.sqlite> --at <canonical-UTC> --approved-digest <sha256> --actor <identity>
19
+
20
+ The tool never discovers or repairs a database automatically. Apply is rejected
21
+ without a verified restorable backup and the exact human-approved dry-run digest.`;
22
+
23
+ function parseArgs(argv = []) {
24
+ const result = { mode: null };
25
+ for (let index = 0; index < argv.length; index += 1) {
26
+ const arg = argv[index];
27
+ if (arg === '--help' || arg === '-h') return { help: true };
28
+ if (arg === '--dry-run' || arg === '--apply') {
29
+ const mode = arg.slice(2);
30
+ if (result.mode && result.mode !== mode) throw new Error('Choose exactly one of --dry-run or --apply');
31
+ result.mode = mode;
32
+ continue;
33
+ }
34
+ const names = {
35
+ '--database': 'databasePath',
36
+ '--backup': 'backupPath',
37
+ '--at': 'observedAt',
38
+ '--approved-digest': 'approvedDigest',
39
+ '--actor': 'actor',
40
+ };
41
+ if (!Object.hasOwn(names, arg)) throw new Error(`Unknown argument: ${arg}`);
42
+ const name = names[arg];
43
+ const value = argv[index + 1];
44
+ if (!value || value.startsWith('--')) throw new Error(`${arg} requires a value`);
45
+ result[name] = value;
46
+ index += 1;
47
+ }
48
+ if (!result.mode) throw new Error('Choose exactly one of --dry-run or --apply');
49
+ for (const required of ['databasePath', 'backupPath', 'observedAt']) {
50
+ if (!result[required]) throw new Error(`Missing required option: ${required}`);
51
+ }
52
+ for (const requiredPath of ['databasePath', 'backupPath']) {
53
+ if (!path.isAbsolute(result[requiredPath])) {
54
+ throw new Error(`${requiredPath} must be an absolute path`);
55
+ }
56
+ }
57
+ if (result.mode === 'apply' && !result.approvedDigest) {
58
+ throw new Error('--apply requires --approved-digest');
59
+ }
60
+ if (result.mode === 'apply' && !result.actor) {
61
+ throw new Error('--apply requires --actor');
62
+ }
63
+ if (result.mode === 'dry-run' && result.approvedDigest) {
64
+ throw new Error('--approved-digest is valid only with --apply');
65
+ }
66
+ if (result.mode === 'dry-run' && result.actor) {
67
+ throw new Error('--actor is valid only with --apply');
68
+ }
69
+ return result;
70
+ }
71
+
72
+ async function run(options, dependencies = {}) {
73
+ const openDriver = dependencies.openDriver
74
+ || (databasePath => createBuiltinSQLiteDriver({ databasePath }));
75
+ const createBackup = dependencies.createVerifiedClaimRepairBackup
76
+ || createVerifiedClaimRepairBackup;
77
+ const hardenPath = dependencies.hardenPath || hardenBackupPermissions;
78
+ const hardenPaths = dependencies.hardenPaths
79
+ || (dependencies.hardenPath ? dependencies.hardenPath.batch : hardenBackupPermissionsBatch);
80
+ const sourceDriver = openDriver(options.databasePath);
81
+ try {
82
+ if (options.mode === 'dry-run') {
83
+ const backup = await createBackup({
84
+ sourceDriver,
85
+ backupPath: options.backupPath,
86
+ observedAt: options.observedAt,
87
+ openDriver,
88
+ hardenPath,
89
+ hardenPaths,
90
+ });
91
+ const preflight = await sourceDriver.preflightLegacyClaimRepair({ observedAt: options.observedAt });
92
+ if (preflight.digest !== backup.plan_digest) {
93
+ throw new ClaimRepairError(
94
+ 'CLAIM_REPAIR_BACKUP_DRIFT',
95
+ 'Live claim authority changed while binding the reported preflight to its verified backup',
96
+ );
97
+ }
98
+ return { ok: true, preflight, backup };
99
+ }
100
+
101
+ const receipt = await sourceDriver.applyLegacyClaimRepair({
102
+ observedAt: options.observedAt,
103
+ approvedDigest: options.approvedDigest,
104
+ backupPath: options.backupPath,
105
+ actor: options.actor,
106
+ });
107
+ return { ok: true, receipt };
108
+ } finally {
109
+ sourceDriver.close();
110
+ }
111
+ }
112
+
113
+ async function main(argv = process.argv.slice(2)) {
114
+ try {
115
+ const options = parseArgs(argv);
116
+ if (options.help) {
117
+ process.stdout.write(`${HELP}\n`);
118
+ return;
119
+ }
120
+ process.stdout.write(`${JSON.stringify(await run(options), null, 2)}\n`);
121
+ } catch (error) {
122
+ const recoveryPath = error?.code === 'CLAIM_REPAIR_BACKUP_POSTCOMMIT_DRIFT'
123
+ && typeof error?.details?.recovery_path === 'string'
124
+ ? error.details.recovery_path
125
+ : null;
126
+ process.stderr.write(`${JSON.stringify({
127
+ ok: false,
128
+ error: {
129
+ code: error?.code || 'CLAIM_REPAIR_USAGE',
130
+ message: error?.message || String(error),
131
+ ...(recoveryPath ? { recovery_path: recoveryPath } : {}),
132
+ },
133
+ }, null, 2)}\n`);
134
+ process.exitCode = 1;
135
+ }
136
+ }
137
+
138
+ if (require.main === module) void main();
139
+
140
+ module.exports = {
141
+ HELP,
142
+ main,
143
+ parseArgs,
144
+ run,
145
+ };
@@ -156,6 +156,7 @@ function createPrAdapter(projectRoot, execFile = execFileSync) {
156
156
  }
157
157
 
158
158
  async function resolveAttribution(projectRoot, head, env, deps = {}) {
159
+ const prExec = deps.runGh ? (_command, args, options) => deps.runGh(args, options) : deps.execFileSync;
159
160
  const branch = resolveBranch(projectRoot, deps.execFileSync);
160
161
  const requestedIssueId = env.FORGE_EVAL_ISSUE_ID;
161
162
  if (requestedIssueId && !UUID.test(String(requestedIssueId))) {
@@ -172,11 +173,11 @@ async function resolveAttribution(projectRoot, head, env, deps = {}) {
172
173
  }
173
174
  const pr = explicitPr
174
175
  ? Number(env.FORGE_EVAL_PR)
175
- : resolvePrFromGh(projectRoot, deps.execFileSync);
176
+ : resolvePrFromGh(projectRoot, prExec);
176
177
  if (!pr) throw new Error('attribution.pr_unavailable');
177
178
  let state;
178
179
  try {
179
- const adapter = deps.prAdapter || createPrAdapter(projectRoot, deps.execFileSync);
180
+ const adapter = deps.prAdapter || createPrAdapter(projectRoot, prExec);
180
181
  state = await adapter.readState(pr);
181
182
  } catch {
182
183
  throw new Error('attribution.pr_unavailable');
@@ -9,6 +9,7 @@ const { spawnSync: defaultSpawnSync } = require('node:child_process');
9
9
  const MANIFEST_ENV = 'FORGE_TEST_PROCESS_MANIFEST';
10
10
  const TOKEN_ENV = 'FORGE_TEST_PROCESS_TOKEN';
11
11
  const INSTANCE_ENV = 'FORGE_TEST_PROCESS_INSTANCE';
12
+ const SESSION_ENV = 'FORGE_SESSION_ID';
12
13
  const MANIFEST_VERSION = 1;
13
14
  const DEFAULT_MANIFEST_DIR = path.join(os.tmpdir(), 'forge-test-processes');
14
15
 
@@ -326,7 +327,11 @@ function createProcessTree(options = {}) {
326
327
  if (!identity && !hasCustomIdentity) return `unverified:${pid}`;
327
328
  return identity;
328
329
  };
329
- const token = String(options.token || env[TOKEN_ENV] || randomUUID());
330
+ // A Forge claim records FORGE_SESSION_ID. Use that same stable runtime token
331
+ // for the root manifest, while preserving an inherited manifest token for
332
+ // nested process trees that are already attached to their parent run.
333
+ const inheritedToken = nonEmptyString(options.token) || nonEmptyString(env[TOKEN_ENV]);
334
+ const token = String(inheritedToken || env[SESSION_ENV] || randomUUID());
330
335
  const explicitManifestPath = nonEmptyString(options.manifestPath);
331
336
  const environmentManifestPath = nonEmptyString(env[MANIFEST_ENV]);
332
337
  const manifestDir = options.manifestDir || DEFAULT_MANIFEST_DIR;
@@ -351,7 +356,11 @@ function createProcessTree(options = {}) {
351
356
  const existing = readProcessManifest(manifestPath, fsApi, processApi);
352
357
  // An environment-provided path may belong to another run. Treat that as
353
358
  // unverifiable and fail closed; never overwrite or reap another run's marker.
354
- const usable = !markerExists || (existing && existing.token === token);
359
+ const inheritedManifestVerified = explicitManifestPath
360
+ || !environmentManifestPath
361
+ || Boolean(inheritedToken && existing?.token === inheritedToken);
362
+ const usable = inheritedManifestVerified
363
+ && (!markerExists || (existing && existing.token === token));
355
364
  let manifest = existing && existing.token === token
356
365
  ? existing
357
366
  : (usable ? createInitialManifest(token, processApi, getProcessIdentity, instanceId) : null);
@@ -749,11 +758,14 @@ function reconcileProcessManifests(options = {}) {
749
758
  }
750
759
 
751
760
  module.exports = {
761
+ DEFAULT_MANIFEST_DIR,
752
762
  INSTANCE_ENV,
753
763
  MANIFEST_ENV,
754
764
  MANIFEST_VERSION,
755
765
  TOKEN_ENV,
756
766
  createProcessTree,
767
+ defaultGetProcessIdentity,
768
+ isValidManifest,
757
769
  readProcessManifest,
758
770
  reapProcessManifest,
759
771
  reconcileProcessManifests,