orbit-thread 1.1.0 → 1.2.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.
@@ -1,8 +1,10 @@
1
1
  # npm publication and releases
2
2
 
3
- Orbit Thread v1.1.0 is the successor to Orbit Handoff v1.0.x.
3
+ Orbit Thread v1.2.1 is a compatibility patch for Orbit Resume (v1.2.0 added Resume to the Orbit Thread line, which succeeded Orbit Handoff v1.0.x in v1.1.0).
4
4
 
5
- Historical `orbit-handoff@1.0.0` and `orbit-handoff@1.0.1` releases are immutable. Do not republish, unpublish or move their release tags.
5
+ `orbit-thread@1.2.0` is already published. v1.2.1 is a new version.
6
+
7
+ Historical `orbit-handoff@1.0.0`, `orbit-handoff@1.0.1`, `orbit-thread@1.1.0` and `orbit-thread@1.2.0` releases are immutable. Do not republish, unpublish or move their release tags.
6
8
 
7
9
  The new primary package is:
8
10
 
@@ -33,15 +35,18 @@ claude plugin validate . --strict
33
35
  Inspect:
34
36
 
35
37
  ```text
36
- orbit-thread-1.1.0.tgz
37
- dist/orbit-thread-plugin-1.1.0.zip
38
+ orbit-thread-1.2.1.tgz
39
+ dist/orbit-thread-plugin-1.2.1.zip
38
40
  ```
39
41
 
40
- Confirm both canonical skills are present:
42
+ The npm tarball should contain 28 files (version 1.2.1, including `lib/resume.mjs` and `plugin/skills/orbit-resume/`). The plugin ZIP should contain the portable `plugin.json`, the three canonical skills and the listing icon. Neither should contain tests, `dist/`, credentials or other build residue.
43
+
44
+ Confirm all three canonical skills are present:
41
45
 
42
46
  ```text
43
47
  plugin/skills/handoff/
44
48
  plugin/skills/orbit-setup/
49
+ plugin/skills/orbit-resume/
45
50
  ```
46
51
 
47
52
  and that the packed CLI can install, setup, configure, doctor, update and uninstall in a disposable repository.
@@ -51,7 +56,7 @@ and that the packed CLI can install, setup, configure, doctor, update and uninst
51
56
  After release checks pass:
52
57
 
53
58
  ```sh
54
- npm publish ./orbit-thread-1.1.0.tgz --access public --registry https://registry.npmjs.org/
59
+ npm publish ./orbit-thread-1.2.1.tgz --access public --registry https://registry.npmjs.org/
55
60
  ```
56
61
 
57
62
  Complete npm's normal browser/2FA challenge if prompted. Never weaken npm account security to automate publication.
@@ -73,7 +78,7 @@ npx orbit-thread@latest doctor --agent both --scope project
73
78
  npx orbit-thread@latest uninstall --agent both --scope project --yes
74
79
  ```
75
80
 
76
- Verify `latest` resolves to `1.1.0` and package metadata points to `shab1h-gh/orbit-thread`.
81
+ Also confirm `npx orbit-thread@latest resume` runs read-only in the disposable repository. Verify `latest` resolves to `1.2.1` and package metadata points to `shab1h-gh/orbit-thread`.
77
82
 
78
83
  ## Existing Orbit Handoff users
79
84
 
@@ -85,7 +90,7 @@ npx orbit-thread@latest setup --agent both --yes
85
90
  npx orbit-thread doctor --agent both --scope project
86
91
  ```
87
92
 
88
- The v1.1 CLI accepts compatible Orbit Handoff ownership/project state and migrates it while refusing locally edited managed files.
93
+ The v1.1 and later CLI accepts compatible Orbit Handoff ownership/project state and migrates it while refusing locally edited managed files.
89
94
 
90
95
  After Orbit Thread is publicly verified, the old package may be deprecated with a migration message, but must not be unpublished:
91
96
 
@@ -1,15 +1,15 @@
1
1
  # Directory submission
2
2
 
3
- Updated 7 October 2026.
3
+ Updated 12 October 2026.
4
4
 
5
5
  Provider-directory review is separate from npm, GitHub and standalone installation.
6
6
 
7
7
  ## OpenAI / ChatGPT Plugins Directory
8
8
 
9
- Orbit Thread v1.1.0 is submitted as:
9
+ Orbit Thread v1.2.1 is submitted as:
10
10
 
11
11
  ```text
12
- dist/orbit-thread-plugin-1.1.0.zip
12
+ dist/orbit-thread-plugin-1.2.1.zip
13
13
  ```
14
14
 
15
15
  Build it with:
@@ -18,14 +18,14 @@ Build it with:
18
18
  npm run build:plugin
19
19
  ```
20
20
 
21
- The ZIP contains portable `plugin.json`, both canonical skills, OpenAI interface metadata, the Orbit Setup onboarding skill, listing icon and compatibility metadata. Orbit Thread needs no MCP server or external account.
21
+ The ZIP contains portable `plugin.json`, all three canonical skills, OpenAI interface metadata, the Orbit Setup onboarding skill, listing icon and compatibility metadata. Orbit Thread needs no MCP server or external account.
22
22
 
23
23
  ### Submission flow
24
24
 
25
- 1. Complete release validation and build the final v1.1.0 ZIP from the release commit/tag.
25
+ 1. Complete release validation and build the final v1.2.1 ZIP from the release commit/tag.
26
26
  2. Open the OpenAI Plugins publisher dashboard:
27
27
  `https://platform.openai.com/plugins`
28
- 3. Upload `orbit-thread-plugin-1.1.0.zip`.
28
+ 3. Upload `orbit-thread-plugin-1.2.1.zip`.
29
29
  4. Complete automated checks and resolve genuine findings.
30
30
  5. Review listing metadata and required policy/data-handling declarations.
31
31
  6. Choose **Submit for review**.
@@ -63,7 +63,7 @@ claude plugin validate ./plugin --strict
63
63
  claude plugin validate . --strict
64
64
  ```
65
65
 
66
- Then use the directory management/submission surface in Claude, connect the GitHub account that owns `shab1h-gh/orbit-thread`, select the repository/plugin, complete the listing details and submit it for review. Use the immutable v1.1.0 release/tag once created.
66
+ Then use the directory management/submission surface in Claude, connect the GitHub account that owns `shab1h-gh/orbit-thread`, select the repository/plugin, complete the listing details and submit it for review. Use the immutable v1.2.1 release/tag once created.
67
67
 
68
68
  A successful GitHub marketplace installation does not mean the plugin is approved for Anthropic's public directory.
69
69
 
@@ -177,3 +177,75 @@ Those native CLIs are not part of GitHub CI, so CI success does not claim those
177
177
 
178
178
  OpenAI and Anthropic public-directory review is separate from npm/GitHub distribution. Their publisher dashboards are authoritative after submission; local validation does not imply approval.
179
179
 
180
+ ## Orbit Resume v1.2.0 validation
181
+
182
+ Release validation completed on 12 October 2026 on the `feature/orbit-resume` branch (PR #3) for v1.2.0. `orbit-thread@1.1.0` was confirmed published on the public npm registry before the version bump; v1.2.0 has not been tagged, published or merged.
183
+
184
+ ### Verified locally for the v1.2.0 release candidate
185
+
186
+ - All 43 automated tests passed, including Codex and Claude project installation,
187
+ reinstall, update, Doctor, missing/invalid/stale handoffs, branch changes,
188
+ future dates, terminal-control sanitisation, secret redaction, and preservation
189
+ of dirty working trees.
190
+ - `npm run validate`, `npm run scan:public`, `npm run build:plugin` and
191
+ `git diff --check` passed.
192
+ - `claude plugin validate ./plugin --strict` and `claude plugin validate . --strict` passed.
193
+ - `npm pack` produced `orbit-thread-1.2.0.tgz` (28 files, including `lib/resume.mjs` and
194
+ `plugin/skills/orbit-resume/`), and `npm run smoke:pack` passed against it in a disposable
195
+ Git project: `resume`, install, setup, configure, Doctor, update and uninstall.
196
+ - `dist/orbit-thread-plugin-1.2.0.zip` contains 16 files: portable and Claude manifests,
197
+ all three skills, icon, licence, privacy and security documents. Both archives report
198
+ version 1.2.0 throughout, with no private paths or build residue.
199
+ - Release metadata (`package.json`, `plugin/plugin.json`, `plugin/.claude-plugin/plugin.json`
200
+ and `.claude-plugin/marketplace.json`) is consistent at 1.2.0; `npm run validate` enforces this.
201
+
202
+ ### Compatibility with v1.1.0 installations
203
+
204
+ Using the published `orbit-thread@1.1.0` from the npm registry, a disposable project was installed
205
+ and set up with `handoff` and `orbit-setup` only, then updated with the packed 1.2.0 CLI.
206
+ Update added `orbit-resume` for Codex and Claude, kept the existing `handoff` and `orbit-setup`
207
+ skills, `.orbit-thread/config.json`, local edits to living docs and user content in `AGENTS.md`, and
208
+ Doctor reported all three skills current at v1.2.0. A locally edited managed skill file was still
209
+ refused with an instruction to preserve changes. The 1.2.0 `resume` command ran read-only,
210
+ and uninstall preserved project docs and configuration.
211
+
212
+ ### Reported native agent testing (not CI)
213
+
214
+ The maintainer reported successful authenticated native testing of the feature-branch skills in fresh
215
+ Codex and Claude Code sessions, using a disposable Git project: Setup, Doctor, handoff
216
+ validation and Resume recovery scenarios passed, and both automatic and explicit manual Resume
217
+ invocation worked in each agent. This was an interactive local test recorded from the
218
+ maintainer's report; it is not part of GitHub CI and was not re-run during release preparation.
219
+ Codex emitted macOS temporary-cache warnings during Git reads but still reported branch,
220
+ status and commit.
221
+
222
+ ### Verified in GitHub CI
223
+
224
+ GitHub CI covers the macOS and Linux Node.js matrix, the test suite, package validation, the
225
+ public-source scan, plugin ZIP generation, `npm pack` and the packed-tarball smoke test. CI does not run
226
+ authenticated Codex or Claude sessions or `claude plugin validate`. The PR #3 CI run on the
227
+ previous commit passed; CI for the release commit is checked on the pull request after push.
228
+
229
+ ### Security review
230
+
231
+ A security review identified a low-risk terminal-control injection through branch metadata in a
232
+ local handoff. Resume strips terminal control sequences from displayed repository and handoff text; a
233
+ regression test confirms they do not reach terminal output.
234
+
235
+ ### Remaining release-gate checks
236
+
237
+ - Merge PR #3, then tag v1.2.0 from the merged release commit.
238
+ - Publish `orbit-thread@1.2.0` and repeat the public-registry smoke test described in
239
+ [PUBLISHING.md](PUBLISHING.md).
240
+
241
+ ## Orbit Resume v1.2.1 validation
242
+
243
+ Compatibility patch (`fix/resume-completed-heading`): Resume now accepts `## Completed this session` as an alias of the canonical `## Completed milestones`. The canonical section takes precedence when both exist; the handoff format is unchanged. The v1.2.0 section above is a historical record and is unchanged.
244
+
245
+ ### Verified locally
246
+
247
+ Results are recorded in the release PR and final report; the checks run were `npm test` (including regression tests for both headings, precedence, missing sections and redaction under the legacy heading), `npm run validate`, `npm run scan:public`, `npm run build:plugin`, `npm pack`, `npm run smoke:pack`, `claude plugin validate ./plugin --strict`, `claude plugin validate . --strict` and `git diff --check`.
248
+
249
+ ### Compatibility with v1.2.0 installations
250
+
251
+ A project installed with the published `orbit-thread@1.2.0` is updated in place by the 1.2.1 CLI; installed skills, `.orbit-thread/config.json`, living docs and existing handoffs are preserved.
package/lib/cli.mjs CHANGED
@@ -6,6 +6,7 @@ import { fileURLToPath } from 'node:url';
6
6
  import { createInterface } from 'node:readline/promises';
7
7
  import { setupProject, checkProject, removeProjectConfig, resolveProjectRoot } from '../plugin/skills/orbit-setup/scripts/setup_project.mjs';
8
8
  import { configureProject, readProjectConfig } from '../plugin/skills/orbit-setup/scripts/project_config.mjs';
9
+ import { resumeProject } from './resume.mjs';
9
10
 
10
11
  const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
11
12
  const pkg = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
@@ -13,7 +14,7 @@ const skillsRoot = path.join(packageRoot, 'plugin/skills');
13
14
  const marker = '.orbit-thread.json';
14
15
  const legacyMarker = '.orbit-handoff.json';
15
16
  const agents = ['codex', 'claude'];
16
- const skills = ['handoff', 'orbit-setup'];
17
+ const skills = ['handoff', 'orbit-setup', 'orbit-resume'];
17
18
  const digest = data => crypto.createHash('sha256').update(data).digest('hex');
18
19
  const exists = p => { try { fs.lstatSync(p); return true; } catch (e) { if (e.code === 'ENOENT') return false; throw e; } };
19
20
 
@@ -143,6 +144,7 @@ Usage: orbit-thread <command> [options]
143
144
  Commands:
144
145
  install Install the Orbit Thread skills.
145
146
  setup Prepare/upgrade the current project workflow and living docs.
147
+ resume Show concise project continuity and current Git state (read-only).
146
148
  configure Set project subagent preferences.
147
149
  doctor Check installed skills and project continuity health.
148
150
  update Upgrade unchanged managed skill files to this package version.
@@ -204,7 +206,7 @@ export async function main(argv) {
204
206
 
205
207
  let [command, ...rest] = argv;
206
208
  if (command === 'init') command = 'setup';
207
- if (!['install', 'setup', 'configure', 'check', 'doctor', 'update', 'uninstall'].includes(command)) throw new Error(`Unknown command: ${command}`);
209
+ if (!['install', 'setup', 'resume', 'configure', 'check', 'doctor', 'update', 'uninstall'].includes(command)) throw new Error(`Unknown command: ${command}`);
208
210
 
209
211
  const options = parseOptions(rest);
210
212
  const scope = options.scope ?? 'project';
@@ -215,6 +217,12 @@ export async function main(argv) {
215
217
  let selected = selectedAgents(options.agent);
216
218
  const root = resolveProjectRoot(process.cwd());
217
219
 
220
+ if (command === 'resume') {
221
+ if (rest.length) throw new Error('resume does not accept options');
222
+ resumeProject(root);
223
+ return;
224
+ }
225
+
218
226
  if (command === 'configure') {
219
227
  if (options.show) { console.log(JSON.stringify(readProjectConfig(root), null, 2)); return; }
220
228
  if ((options.model !== undefined || options.reasoning !== undefined) && selected.length !== 1) {
package/lib/resume.mjs ADDED
@@ -0,0 +1,164 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { execFileSync } from 'node:child_process';
4
+
5
+ const handoffPath = root => path.join(root, 'HANDOFF-STATE.md');
6
+ const secret = /\b(api[_ -]?key|access[_ -]?token|refresh[_ -]?token|password|secret|authorization|bearer)\b\s*[:=]\s*[^\s,;]+/gi;
7
+
8
+ function scrub(value) {
9
+ const safe = value.slice(0, 500)
10
+ .replace(/\u001b\][^\u0007]*(?:\u0007|\u001b\\)/g, '')
11
+ .replace(/\u001b\[[0-?]*[ -/]*[@-~]/g, '')
12
+ .replace(/\u009b[0-?]*[ -/]*[@-~]/g, '')
13
+ .replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f]/g, '');
14
+ if (/\b(?:password|passphrase|token|secret|credential|private\s+key|api[_ -]?key|authorization|bearer)\b/i.test(safe)) {
15
+ return '[redacted sensitive-looking handoff line]';
16
+ }
17
+ return safe.replace(secret, '$1=[redacted]');
18
+ }
19
+
20
+ function readHandoff(root) {
21
+ const file = handoffPath(root);
22
+ try {
23
+ const stat = fs.lstatSync(file);
24
+ if (stat.isSymbolicLink() || !stat.isFile()) return { state: 'invalid', reason: 'not a regular local file' };
25
+ if (stat.size > 32768) return { state: 'invalid', reason: 'larger than the 32 KB safety limit' };
26
+ const text = fs.readFileSync(file, 'utf8');
27
+ const lines = text.split(/\r?\n/);
28
+ if (lines.length > 51) return { state: 'invalid', reason: 'over the 50-line limit' };
29
+ if (!/^# Handoff State\s*$/m.test(text)) return { state: 'invalid', reason: 'missing the Handoff State heading' };
30
+ const updated = text.match(/^Updated:\s*(\d{2})-(\d{2})-(\d{4})(?:\s+\d{2}:\d{2})?\s*$/m);
31
+ const objective = section(text, 'Current objective');
32
+ if (!updated || !objective.length) return { state: 'invalid', reason: 'missing a valid update date or current objective' };
33
+ const date = new Date(Number(updated[3]), Number(updated[2]) - 1, Number(updated[1]));
34
+ if (Number.isNaN(date.valueOf()) || date.getDate() !== Number(updated[1]) || date.getMonth() !== Number(updated[2]) - 1) {
35
+ return { state: 'invalid', reason: 'invalid update date' };
36
+ }
37
+ return {
38
+ state: 'valid', text, updated: `${updated[3]}-${updated[2]}-${updated[1]}`,
39
+ fields: {
40
+ objective,
41
+ completed: firstSection(text, ['Completed milestones', 'Completed this session']),
42
+ unfinished: section(text, 'In progress'),
43
+ risks: section(text, 'Open issues / risks'),
44
+ verification: section(text, 'Verification'),
45
+ next: section(text, 'Immediate next steps'),
46
+ },
47
+ };
48
+ } catch (error) {
49
+ if (error.code === 'ENOENT') return { state: 'missing' };
50
+ throw error;
51
+ }
52
+ }
53
+
54
+ function section(text, title) {
55
+ const escaped = title.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
56
+ const match = text.match(new RegExp(`^##\\s+${escaped}\\s*\\r?\\n([\\s\\S]*?)(?=^##\\s+|(?![\\s\\S]))`, 'm'));
57
+ if (!match) return [];
58
+ return match[1].split(/\r?\n/).map(line => line.trim()).filter(line => line && !/^<!--/.test(line)).slice(0, 6).map(line => scrub(line));
59
+ }
60
+
61
+ // Canonical heading first; legacy alias only used when the canonical section is absent or empty.
62
+ function firstSection(text, titles) {
63
+ for (const title of titles) {
64
+ const lines = section(text, title);
65
+ if (lines.length) return lines;
66
+ }
67
+ return [];
68
+ }
69
+
70
+ function git(root, args) {
71
+ try {
72
+ return execFileSync('git', args, { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeout: 3000 }).trim();
73
+ } catch { return null; }
74
+ }
75
+
76
+ function currentGit(root) {
77
+ const branch = git(root, ['symbolic-ref', '--short', '-q', 'HEAD']) ?? (git(root, ['rev-parse', '--short', 'HEAD']) ? 'detached HEAD' : null);
78
+ const status = git(root, ['status', '--short', '--untracked-files=normal']);
79
+ const commitDate = git(root, ['log', '-1', '--format=%cs']);
80
+ const changed = (status ?? '').split(/\r?\n/).filter(Boolean);
81
+ const safeChanged = changed.filter(line => !/(^|\s)(?:\.env(?:\.|\s|$)|\.dev\.vars(?:\s|$)|.*(?:secret|credential|private[_-]?key|id_rsa|id_ed25519|\.pem|\.key|\.netrc|\.npmrc|\.pypirc).*)/i.test(line));
82
+ return { branch, status, changed: safeChanged.slice(0, 8), count: changed.length, commitDate };
83
+ }
84
+
85
+ function relevantDocs(text, root) {
86
+ const topics = [
87
+ ['PRODUCT.md', /product|workflow|scope|user-facing|feature/i],
88
+ ['DESIGN.md', /ui|ux|design|layout|visual|accessibility/i],
89
+ ['ARCHITECTURE.md', /architecture|runtime|data flow|integration|database|storage|deploy/i],
90
+ ['SECURITY.md', /auth|security|permission|secret|tenant|trust|privacy/i],
91
+ ['ROADMAP.md', /roadmap|plan|milestone|later|defer/i],
92
+ ];
93
+ const matches = [];
94
+ for (const [name, pattern] of topics) {
95
+ if (!pattern.test(text)) continue;
96
+ for (const file of [path.join(root, name), path.join(root, 'docs', name)]) {
97
+ try {
98
+ if (fs.lstatSync(file).isFile() && !fs.lstatSync(file).isSymbolicLink()) { matches.push(path.relative(root, file)); break; }
99
+ } catch (error) { if (error.code !== 'ENOENT') throw error; }
100
+ }
101
+ }
102
+ return [...new Set(matches)].slice(0, 3);
103
+ }
104
+
105
+ function printLines(label, lines, fallback) {
106
+ console.log(`${label}:`);
107
+ if (!lines.length) console.log(` ${fallback}`);
108
+ else lines.forEach(line => console.log(` ${line}`));
109
+ }
110
+
111
+ export function resumeProject(root) {
112
+ root = path.resolve(root);
113
+ const handoff = readHandoff(root);
114
+ const gitState = currentGit(root);
115
+ let status = handoff.state;
116
+ let reason = handoff.reason;
117
+ const recordedBranch = handoff.state === 'valid' ? handoff.text.match(/^(?:current\s+)?branch:\s*([^\s]+)/im)?.[1] : null;
118
+ if (recordedBranch && gitState.branch) {
119
+ if (recordedBranch !== gitState.branch) { status = 'possibly outdated'; reason = `recorded branch ${recordedBranch} differs from current branch`; }
120
+ }
121
+ const today = new Date();
122
+ const todayDate = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
123
+ if (handoff.state === 'valid' && handoff.updated && handoff.updated > todayDate) {
124
+ status = 'possibly outdated';
125
+ reason = 'handoff date is in the future';
126
+ }
127
+ if (handoff.state === 'valid' && gitState.commitDate && handoff.updated && gitState.commitDate > handoff.updated) {
128
+ status = 'possibly outdated';
129
+ reason = `Git has a commit dated ${gitState.commitDate}, after the handoff date`;
130
+ }
131
+
132
+ console.log('Orbit Resume (read-only)');
133
+ console.log(`Project: ${scrub(path.basename(root))}`);
134
+ console.log(`Handoff: ${status}${reason ? ` — ${scrub(reason)}` : ''}`);
135
+ if (handoff.state === 'valid') {
136
+ const usable = status === 'valid';
137
+ printLines('Objective', usable ? handoff.fields.objective : [], usable ? 'Not recorded.' : 'Treat the handoff as a lead; current repository evidence takes precedence.');
138
+ printLines('Completed milestones', usable ? handoff.fields.completed : [], 'No verified milestones recorded.');
139
+ printLines('Unfinished work', usable ? handoff.fields.unfinished : [], 'No in-progress work recorded.');
140
+ printLines('Risks', usable ? handoff.fields.risks : [], 'No risks recorded.');
141
+ printLines('Verification', usable ? handoff.fields.verification : [], 'No verification recorded.');
142
+ } else {
143
+ printLines('Objective', [], 'Unknown; do not infer it from an absent or invalid handoff.');
144
+ printLines('Completed milestones', [], 'No reliable handoff evidence.');
145
+ printLines('Unfinished work', [], 'Check the current task and Git changes before proceeding.');
146
+ printLines('Risks', [], handoff.state === 'invalid' ? 'Handoff was not used because it is invalid.' : 'No handoff exists yet.');
147
+ printLines('Verification', [], 'No reliable handoff evidence.');
148
+ }
149
+
150
+ console.log('Git status:');
151
+ if (!gitState.branch && gitState.status === null) console.log(' Git repository unavailable.');
152
+ else {
153
+ console.log(` Branch: ${scrub(gitState.branch ?? 'unknown')}`);
154
+ console.log(` Working tree: ${gitState.count ? `dirty (${gitState.count} change${gitState.count === 1 ? '' : 's'})` : 'clean'}`);
155
+ gitState.changed.forEach(line => console.log(` ${scrub(line)}`));
156
+ if (gitState.count > gitState.changed.length) console.log(` ${gitState.count - gitState.changed.length} sensitive-looking path(s) omitted.`);
157
+ }
158
+
159
+ const trustedNext = handoff.state === 'valid' && status === 'valid' ? handoff.fields.next : [];
160
+ const docs = relevantDocs([...(trustedNext.length ? trustedNext : []), ...(handoff.state === 'valid' ? handoff.fields.objective : [])].join(' '), root);
161
+ printLines('Next steps', trustedNext, handoff.state === 'valid' && status === 'valid' ? 'No next step recorded; inspect current changes and choose one from repository evidence.' : 'Inspect current Git changes, then identify the next action from the user request and tracked project docs.');
162
+ printLines('Relevant living docs', docs, 'None identified from the handoff; load a living doc only if the next action needs it.');
163
+ console.log('Keep unfinished working changes. Do not reset or clean the repository. Current Git and tracked docs override stale handoff details.');
164
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orbit-thread",
3
- "version": "1.1.0",
3
+ "version": "1.2.1",
4
4
  "description": "Token-efficient project setup, checkpoints and coding-session continuity for Codex and Claude Code.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,7 +14,7 @@
14
14
  "repository": { "type": "git", "url": "git+https://github.com/shab1h-gh/orbit-thread.git" },
15
15
  "homepage": "https://github.com/shab1h-gh/orbit-thread#readme",
16
16
  "bugs": { "url": "https://github.com/shab1h-gh/orbit-thread/issues" },
17
- "keywords": ["codex", "claude-code", "agent-skills", "continuity", "project-setup", "handoff", "context-efficiency"],
17
+ "keywords": ["codex", "claude-code", "agent-skills", "continuity", "project-setup", "handoff", "resume", "context-efficiency"],
18
18
  "files": ["bin/", "lib/", "plugin/", "docs/", "README.md", "LICENSE", "SECURITY.md", "PRIVACY.md", "CONTRIBUTING.md", "CHANGELOG.md"],
19
19
  "scripts": {
20
20
  "test": "node --test",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "orbit-thread",
3
3
  "displayName": "Orbit Thread",
4
- "version": "1.1.0",
4
+ "version": "1.2.1",
5
5
  "description": "Token-efficient project setup, checkpoints and coding-session continuity.",
6
6
  "author": { "name": "Shabih Anwar", "url": "https://github.com/shab1h-gh" },
7
7
  "homepage": "https://github.com/shab1h-gh/orbit-thread",
@@ -11,6 +11,6 @@
11
11
  "documentationUrl": "https://github.com/shab1h-gh/orbit-thread#readme",
12
12
  "supportUrl": "https://github.com/shab1h-gh/orbit-thread/issues",
13
13
  "privacyPolicyUrl": "https://github.com/shab1h-gh/orbit-thread/blob/main/PRIVACY.md",
14
- "keywords": ["continuity", "handoff", "project-setup", "developer-tools"],
14
+ "keywords": ["continuity", "handoff", "resume", "project-setup", "developer-tools"],
15
15
  "skills": "./skills/"
16
16
  }
package/plugin/README.md CHANGED
@@ -1,25 +1,27 @@
1
1
  # Orbit Thread
2
2
 
3
- Orbit Thread provides two local coding skills:
3
+ Orbit Thread provides three local coding skills:
4
4
 
5
5
  - **Orbit Setup** prepares a project with lightweight living docs, selective context rules and configurable subagent preferences.
6
6
  - **Handoff** overwrites a compact, evidence-only `HANDOFF-STATE.md` so a fresh coding session can resume from Git + current project truth rather than a large old conversation.
7
+ - **Resume** reconstructs concise project context from the latest usable handoff, current Git state and task-relevant living docs.
7
8
 
8
9
  Standalone commands:
9
10
 
10
- - Codex: `$orbit-setup` and `$handoff`
11
- - Claude Code: `/orbit-setup` and `/handoff`
11
+ - Codex: `$orbit-setup`, `$handoff` and `$orbit-resume`
12
+ - Claude Code: `/orbit-setup`, `/handoff` and `/orbit-resume`
12
13
 
13
14
  Claude plugin commands:
14
15
 
15
16
  - `/orbit-thread:orbit-setup`
16
17
  - `/orbit-thread:handoff`
18
+ - `/orbit-thread:orbit-resume`
17
19
 
18
20
  Setup creates only missing PRODUCT, DESIGN, ARCHITECTURE, SECURITY and ROADMAP templates, preserves existing equivalents, manages a concise Orbit Thread section in AGENTS.md/CLAUDE.md, and keeps local handoff/tool state Git-ignored.
19
21
 
20
- The project rules update living docs in place, load only relevant context, default to no subagents with a maximum of two, and request Handoff after meaningful verified milestones/completed coding tasks.
22
+ Start each coding task in a fresh chat and run Resume once at session start, automatically where supported or manually as a fallback. The project rules update living docs in place, load only relevant context, default to no subagents with a maximum of two, and request Handoff after meaningful verified milestones/completed coding tasks.
21
23
 
22
- Handoff is overwrite-only, capped at 50 lines, secret-checked before atomic replacement and makes no network calls or Git mutations.
24
+ Handoff is overwrite-only, capped at 50 lines, secret-checked before atomic replacement and makes no network calls or Git mutations. Resume and `npx orbit-thread resume` are read-only and preserve unfinished work.
23
25
 
24
26
  There is no MCP server, telemetry or external account.
25
27
 
@@ -1,26 +1,26 @@
1
1
  {
2
2
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
3
  "name": "orbit-thread",
4
- "version": "1.1.0",
4
+ "version": "1.2.1",
5
5
  "description": "Token-efficient project setup, checkpoints and coding-session continuity.",
6
6
  "author": { "name": "Shabih Anwar", "url": "https://github.com/shab1h-gh" },
7
7
  "homepage": "https://github.com/shab1h-gh/orbit-thread",
8
8
  "repository": "https://github.com/shab1h-gh/orbit-thread",
9
9
  "license": "MIT",
10
- "keywords": ["handoff", "codex", "claude-code", "continuity", "project-setup", "developer-tools"],
10
+ "keywords": ["handoff", "resume", "codex", "claude-code", "continuity", "project-setup", "developer-tools"],
11
11
  "extensions": {
12
12
  "com.openai": {
13
13
  "interface": {
14
14
  "displayName": "Orbit Thread",
15
15
  "shortDescription": "Lean coding continuity",
16
- "longDescription": "Orbit Thread gives coding agents a small, durable continuity layer. Orbit Setup creates only missing PRODUCT, DESIGN, ARCHITECTURE, SECURITY and ROADMAP living docs, adds selective context-loading and bounded-subagent rules, and keeps local execution state separate from tracked project truth. Handoff then overwrites a compact HANDOFF-STATE.md at meaningful verified checkpoints and completed coding tasks so a fresh session can resume from Git, current docs and the exact next action instead of carrying a large chat history. Handoffs are capped at 50 lines, validated before atomic replacement, and the writer makes no network calls or Git mutations. Existing project docs and unrelated instructions are preserved.",
16
+ "longDescription": "Orbit Thread gives coding agents a small, durable continuity layer. Orbit Setup creates only missing PRODUCT, DESIGN, ARCHITECTURE, SECURITY and ROADMAP living docs, adds selective context-loading and bounded-subagent rules, and keeps local execution state separate from tracked project truth. Handoff overwrites a compact HANDOFF-STATE.md at verified checkpoints. Resume starts a fresh chat from the current handoff, read-only Git state and only the living docs needed for the task, reducing repeated context while preserving unfinished changes. Handoffs are capped at 50 lines, validated before atomic replacement, and the writer makes no network calls or Git mutations. Existing project docs and unrelated instructions are preserved.",
17
17
  "developerName": "Shabih Anwar",
18
18
  "category": "Developer Tools",
19
- "capabilities": ["Prepare project continuity", "Save verified coding checkpoints"],
19
+ "capabilities": ["Prepare project continuity", "Save verified coding checkpoints", "Resume coding sessions"],
20
20
  "websiteURL": "https://github.com/shab1h-gh/orbit-thread",
21
21
  "supportURL": "https://github.com/shab1h-gh/orbit-thread/issues",
22
22
  "privacyPolicyURL": "https://github.com/shab1h-gh/orbit-thread/blob/main/PRIVACY.md",
23
- "defaultPrompt": ["Prepare this coding project for efficient continuity, or save verified current state at a meaningful checkpoint."],
23
+ "defaultPrompt": ["Prepare this coding project for efficient continuity, resume a fresh coding session, or save verified current state at a meaningful checkpoint."],
24
24
  "brandColor": "#4338CA",
25
25
  "composerIcon": "./assets/icon.png",
26
26
  "logo": "./assets/icon.png"
@@ -41,6 +41,7 @@ Omit empty sections. Aim for about 30 lines; hard cap 50. State each fact once.
41
41
  - Evidence only. Never claim a test, deployment, commit, push or external action happened without evidence.
42
42
  - Never include secrets, credentials, tokens, private keys, recovery codes, `.env`/`.dev.vars` values, personal data or sensitive production data.
43
43
  - Do not record the current HEAD SHA; it becomes stale easily. Exact SHAs are allowed only for immutable earlier revisions such as releases, deployments or rollback points.
44
+ - When Git is available, record the current branch as `Branch: <name>` under `Current state` so a later Resume can detect a branch change. Never record the current HEAD SHA.
44
45
  - `HANDOFF-STATE.md` is local current state, intended to be Git-ignored. Never append history or make committing it a next step.
45
46
  - Durable product, design, architecture, security or roadmap truth belongs in tracked living docs. Handoff does not replace those files.
46
47
  - At an intermediate checkpoint, do not stop merely because the handoff was written.
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: orbit-resume
3
+ description: Recover essential project context at the start of a fresh Codex or Claude Code conversation from the latest usable handoff, current Git state and only the living docs needed for the current task. Use once per new coding session, or when the user explicitly asks to resume project work.
4
+ ---
5
+
6
+ # Orbit Thread Resume
7
+
8
+ Recover the current project state once at the beginning of a fresh coding conversation. Keep the context small and preserve unfinished changes.
9
+
10
+ ## Workflow
11
+
12
+ 1. If the user already supplied output from `npx orbit-thread resume` in this conversation, use it. Otherwise inspect `HANDOFF-STATE.md` once if it exists, then run read-only `git status --short --branch`, `git diff --stat HEAD`, and `git log -1 --oneline` from the project root. Do not invoke npm, install tools, or search the repository broadly.
13
+ 2. Treat the handoff as a lead. Current Git state and tracked project docs override stale or conflicting handoff details. A missing or malformed handoff is not a reason to invent the objective or completed work; use the user's current request and state what remains unknown.
14
+ 3. Preserve all dirty and untracked work. Never reset, clean, stash, stage, commit, checkout, deploy, or otherwise change repository state.
15
+ 4. Read only the living doc that directly informs the current requested task: PRODUCT for scope or behaviour, DESIGN for UI, ARCHITECTURE for runtime/data flow, SECURITY for trust/auth/secrets, ROADMAP for planning. Use its existing root or `docs/` location. Do not load unrelated docs or repeat facts already clear from the handoff.
16
+ 5. Give the user a compact summary of the objective, verified milestones, unfinished work, risks, verification, Git state, and immediate next action. Separate facts from unknowns. End with one clear next action grounded in the current request and repository evidence.
17
+
18
+ Run this skill once per fresh conversation. Do not repeat it during the same session unless the user asks for a fresh recovery. If the host cannot invoke it automatically, the reliable fallback is `$orbit-resume` in Codex, `/orbit-resume` in Claude Code, or `/orbit-thread:orbit-resume` from the Claude marketplace plugin.
19
+
20
+ ## Safety
21
+
22
+ - Read only the handoff, Git summaries, and task-relevant living docs. Never read `.env`, `.dev.vars`, credentials, private keys, or unrelated files.
23
+ - Do not echo secret-looking values or sensitive local file paths. Keep the user's unfinished work intact.
24
+ - The `npx orbit-thread resume` CLI command is read-only and can be run by the developer for a concise terminal summary. Do not run `npx` from this skill because it can download packages when the CLI is unavailable.
25
+ - Do not claim a check, test, deployment, commit, or external action unless current evidence confirms it.
@@ -0,0 +1,6 @@
1
+ interface:
2
+ display_name: "Orbit Thread Resume"
3
+ short_description: "Recover concise project context"
4
+ default_prompt: "Use $orbit-resume once to recover the verified project state and next action for this fresh coding session."
5
+ policy:
6
+ allow_implicit_invocation: true
@@ -28,8 +28,9 @@ const agentsBlock = config => `${begin}
28
28
  - Inspect only source files needed for the task. Do not broadly scan generated, vendor, dependency, build, coverage or cache directories, and do not reread unchanged context without a reason.
29
29
  - Living docs describe CURRENT truth. After verified work changes that truth, update affected existing sections in place during the same milestone. Never append session diaries or duplicate superseded sections; Git is history. Never rewrite an applied migration.
30
30
  - Run the smallest relevant verification before claiming a milestone or task complete. Never claim a test, deployment, commit, push or external action that did not run.
31
+ - Start each new coding task in a fresh chat and invoke \`$orbit-resume\` once at session start. Do this automatically where the host supports it; otherwise the reliable fallback is to invoke it manually. Do not repeat Resume in the same session unless the user asks for a fresh recovery.
31
32
  - Run the installed \`handoff\` skill after a meaningful verified milestone that changed repository state or durable project truth, and after each completed coding task with such changes before the final reply. Also checkpoint before \`/clear\`, session end, or a usage/context stop when warning is available. Skip read-only questions and trivial edits. Intermediate checkpoints must not stop unfinished work.
32
- - Each checkpoint overwrites \`HANDOFF-STATE.md\`. After a fresh/cleared/recovered session: read the handoff once if present, inspect branch/status/diff/recent log, read only relevant living docs, then inspect only source needed for the exact next action. Do not reconstruct old conversation history or repeat completed work.
33
+ - Each checkpoint overwrites \`HANDOFF-STATE.md\`. Resume reads the handoff once if present, checks current Git state, then reads only task-relevant living docs and source. Do not reconstruct old conversation history or repeat completed work.
33
34
  ${renderSubagentBlock(config)}
34
35
  - Read-only Git inspection is allowed. Commit, push, merge, rebase, reset, branch deletion or other Git writes require explicit authority in the current request. Never force-push or destructively clean without explicit authority.
35
36
  - Never place secrets, credentials, environment values, private keys, recovery codes, personal data or sensitive production data in living docs or \`HANDOFF-STATE.md\`.
@@ -39,7 +40,7 @@ ${end}
39
40
  const claudeBlock = `${begin}
40
41
  ## Orbit Thread
41
42
 
42
- Read and follow \`AGENTS.md\` for project workflow, selective context loading, subagents and checkpoints. On a fresh or recovered session, resume from \`HANDOFF-STATE.md\` + current Git state + only the relevant living docs instead of reconstructing old conversation history.
43
+ Read and follow \`AGENTS.md\` for project workflow, selective context loading, subagents and checkpoints. Start each new coding task in a fresh chat and invoke \`/orbit-resume\` once at session start, automatically where supported. If automatic invocation is unavailable, manually run \`/orbit-resume\` (or \`/orbit-thread:orbit-resume\` from the marketplace plugin). Do not repeat Resume in the same session unless the user asks for a fresh recovery.
43
44
  ${end}
44
45
  `;
45
46
  const templates = {