@varman96/paper 0.0.0-stage → 1.0.0

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 (4) hide show
  1. package/LICENSE +164 -0
  2. package/README.md +147 -2
  3. package/dist/paper.js +64 -0
  4. package/package.json +46 -5
package/LICENSE ADDED
@@ -0,0 +1,164 @@
1
+ # PolyForm Shield License 1.0.0
2
+
3
+ <https://polyformproject.org/licenses/shield/1.0.0>
4
+
5
+ ## Acceptance
6
+
7
+ In order to get any license under these terms, you must agree
8
+ to them as both strict obligations and conditions to all
9
+ your licenses.
10
+
11
+ ## Copyright License
12
+
13
+ The licensor grants you a copyright license for the
14
+ software to do everything you might do with the software
15
+ that would otherwise infringe the licensor's copyright
16
+ in it for any permitted purpose. However, you may
17
+ only distribute the software according to [Distribution
18
+ License](#distribution-license) and make changes or new works
19
+ based on the software according to [Changes and New Works
20
+ License](#changes-and-new-works-license).
21
+
22
+ ## Distribution License
23
+
24
+ The licensor grants you an additional copyright license
25
+ to distribute copies of the software. Your license
26
+ to distribute covers distributing the software with
27
+ changes and new works permitted by [Changes and New Works
28
+ License](#changes-and-new-works-license).
29
+
30
+ ## Notices
31
+
32
+ You must ensure that anyone who gets a copy of any part of
33
+ the software from you also gets a copy of these terms or the
34
+ URL for them above, as well as copies of any plain-text lines
35
+ beginning with `Required Notice:` that the licensor provided
36
+ with the software. For example:
37
+
38
+ > Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
39
+
40
+ ## Changes and New Works License
41
+
42
+ The licensor grants you an additional copyright license to
43
+ make changes and new works based on the software for any
44
+ permitted purpose.
45
+
46
+ ## Patent License
47
+
48
+ The licensor grants you a patent license for the software that
49
+ covers patent claims the licensor can license, or becomes able
50
+ to license, that you would infringe by using the software.
51
+
52
+ ## Noncompete
53
+
54
+ Any purpose is a permitted purpose, except for providing any
55
+ product that competes with the software or any product the
56
+ licensor or any of its affiliates provides using the software.
57
+
58
+ ## Competition
59
+
60
+ Goods and services compete even when they provide functionality
61
+ through different kinds of interfaces or for different technical
62
+ platforms. Applications can compete with services, libraries
63
+ with plugins, frameworks with development tools, and so on,
64
+ even if they're written in different programming languages
65
+ or for different computer architectures. Goods and services
66
+ compete even when provided free of charge. If you market a
67
+ product as a practical substitute for the software or another
68
+ product, it definitely competes.
69
+
70
+ ## New Products
71
+
72
+ If you are using the software to provide a product that does
73
+ not compete, but the licensor or any of its affiliates brings
74
+ your product into competition by providing a new version of
75
+ the software or another product using the software, you may
76
+ continue using versions of the software available under these
77
+ terms beforehand to provide your competing product, but not
78
+ any later versions.
79
+
80
+ ## Discontinued Products
81
+
82
+ You may begin using the software to compete with a product
83
+ or service that the licensor or any of its affiliates has
84
+ stopped providing, unless the licensor includes a plain-text
85
+ line beginning with `Licensor Line of Business:` with the
86
+ software that mentions that line of business. For example:
87
+
88
+ > Licensor Line of Business: YoyodyneCMS Content Management
89
+ System (http://example.com/cms)
90
+
91
+ ## Sales of Business
92
+
93
+ If the licensor or any of its affiliates sells a line of
94
+ business developing the software or using the software
95
+ to provide a product, the buyer can also enforce
96
+ [Noncompete](#noncompete) for that product.
97
+
98
+ ## Fair Use
99
+
100
+ You may have "fair use" rights for the software under the
101
+ law. These terms do not limit them.
102
+
103
+ ## No Other Rights
104
+
105
+ These terms do not allow you to sublicense or transfer any of
106
+ your licenses to anyone else, or prevent the licensor from
107
+ granting licenses to anyone else. These terms do not imply
108
+ any other licenses.
109
+
110
+ ## Patent Defense
111
+
112
+ If you make any written claim that the software infringes or
113
+ contributes to infringement of any patent, your patent license
114
+ for the software granted under these terms ends immediately. If
115
+ your company makes such a claim, your patent license ends
116
+ immediately for work on behalf of your company.
117
+
118
+ ## Violations
119
+
120
+ The first time you are notified in writing that you have
121
+ violated any of these terms, or done anything with the software
122
+ not covered by your licenses, your licenses can nonetheless
123
+ continue if you come into full compliance with these terms,
124
+ and take practical steps to correct past violations, within
125
+ 32 days of receiving notice. Otherwise, all your licenses
126
+ end immediately.
127
+
128
+ ## No Liability
129
+
130
+ ***As far as the law allows, the software comes as is, without
131
+ any warranty or condition, and the licensor will not be liable
132
+ to you for any damages arising out of these terms or the use
133
+ or nature of the software, under any kind of legal claim.***
134
+
135
+ ## Definitions
136
+
137
+ The **licensor** is the individual or entity offering these
138
+ terms, and the **software** is the software the licensor makes
139
+ available under these terms.
140
+
141
+ A **product** can be a good or service, or a combination
142
+ of them.
143
+
144
+ **You** refers to the individual or entity agreeing to these
145
+ terms.
146
+
147
+ **Your company** is any legal entity, sole proprietorship,
148
+ or other kind of organization that you work for, plus all
149
+ its affiliates.
150
+
151
+ **Affiliates** means the other organizations than an
152
+ organization has control over, is under the control of, or is
153
+ under common control with.
154
+
155
+ **Control** means ownership of substantially all the assets of
156
+ an entity, or the power to direct its management and policies
157
+ by vote, contract, or otherwise. Control can be direct or
158
+ indirect.
159
+
160
+ **Your licenses** are all the licenses granted to you for the
161
+ software under these terms.
162
+
163
+ **Use** means anything you do with the software requiring one
164
+ of your licenses.
package/README.md CHANGED
@@ -1,3 +1,148 @@
1
- # Temporary Holding Version
1
+ # Paper
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Paper turns messy debugging context into a clean Incident Report you can paste into Claude, Cursor, Codex, ChatGPT, or Gemini.
4
+
5
+ ---
6
+
7
+ ## Features
8
+
9
+ - **Block-Based Text Editor**: Minimalist text editor that structures content into individual blocks, supporting bold, italic, and bullet lists with Markdown serialization.
10
+ - **Investigative Incident Report**: Orders runtime evidence through Scope, Delta, Failure Boundary, Execution Path, Evidence, falsified hypotheses, a supported working hypothesis, and the next test.
11
+ - **Copy for AI**: Generates the packet locally in the browser and copies it for use in the AI coding tool of your choice.
12
+ - **Note Management**: Create, delete, switch between notes, and clear sample notes. Notes auto-save to browser local storage.
13
+ - **Markdown Export**: Export notes directly to `.md` files.
14
+ - **Local-first workflow**: The packet builder does not require an AI call or backend persistence.
15
+
16
+ ---
17
+
18
+ ## System Architecture
19
+
20
+ Paper consists of a static client-side application and API endpoints deployed through a Cloudflare Worker with static assets. The public landing page is served at `/`, and the packet builder is served at `/app/`.
21
+
22
+ ```
23
+ paper/
24
+ ├── index.html # Public landing page
25
+ ├── app/
26
+ │ └── index.html # Manual packet fallback shell served at /app/
27
+ ├── styles.css # Application styling
28
+ ├── app.js # Application entry point and module coordination
29
+ ├── js/
30
+ │ ├── debug-packet.js # Shared canonical packet schema and Markdown generator
31
+ │ ├── state.js # Central application state and getters
32
+ │ ├── storage.js # LocalStorage persistence and note schema creation
33
+ │ ├── editor.js # Block editor management, input handling, and character caps
34
+ │ ├── formatting.js # Selection toolbar and inline formatting commands
35
+ │ ├── manual/
36
+ │ │ └── debug-packet.js # Retained manual fallback packet UI logic
37
+ │ ├── notes.js # Note list management, title derivation, and export
38
+ │ ├── mobile.js # Mobile navigation drawer and responsive panels
39
+ │ └── utils.js # HTML sanitization and string helpers
40
+ ├── legacy/
41
+ │ └── review/
42
+ │ ├── review.js # Dormant legacy Review coordination
43
+ │ └── critique-ui.js # Dormant legacy Review rendering
44
+ ├── scripts/
45
+ │ ├── build-assets.js # Builds the root + /app/ static asset layout
46
+ │ └── paper.js # Local stdin CLI ingestion and deterministic extraction
47
+ ├── .paper/
48
+ │ └── incident_report.md # Canonical investigative report template
49
+ ├── worker.js # Routes /api/* before static assets
50
+ └── api/
51
+ └── lib/
52
+ ├── gemini.js # Gemini API client with retry logic
53
+ ├── rate-limit.js # Sliding-window IP rate limiter
54
+ ├── review-prompt.js# System and user prompt construction
55
+ └── review-schema.js# Input normalization and response parsing
56
+ ```
57
+
58
+ The current web form is retained as a manual fallback/reference under the explicit `manual-fallback` surface. The CLI and `.paper/incident_report.md` use the same canonical investigative schema. The fallback remains directly available at `/app/`.
59
+
60
+ ---
61
+
62
+ ## How It Works
63
+
64
+ ### 1. Document Editing and Storage
65
+
66
+ - When the user types in the editor, DOM nodes are parsed and serialized into blocks.
67
+ - Notes are stored in the browser's `localStorage` under the key `paper.notes.v1`.
68
+ - The document title is automatically inferred from the first line of text unless manually modified by the user.
69
+ - Document editing and storage do not impose an AI-driven character limit.
70
+
71
+ ### 2. The Incident Report Workflow
72
+
73
+ 1. **Capture**: Collect runtime evidence in the CLI, incident template, or manual fallback.
74
+ 2. **Structure**: Organize it in investigative order from Scope through Next Test.
75
+ 3. **Generate Markdown**: Generate one deterministic packet locally.
76
+ 4. **Copy for AI**: Copy the packet into Claude, Cursor, Codex, ChatGPT, or Gemini.
77
+
78
+ ### 3. Terminal-first prototype
79
+
80
+ The local prototype accepts stdin and emits the same deterministic packet format without making model, backend, or network calls:
81
+
82
+ ```bash
83
+ some-command 2>&1 | npm.cmd run paper
84
+ ```
85
+
86
+ The complete stdin text is retained under Evidence as an Other deterministic receipt. Only directly recognizable error lines, status codes, stack frames, paths, command lines, and runtime hints are placed into additional fields; unsupported fields remain empty.
87
+
88
+ ### 4. Retired sharing
89
+
90
+ Document sharing is not part of the active application. The historical implementation is preserved under `legacy/sharing/` for reference and emergency recovery only; it must not be imported or published as an asset. Old share fragments are ignored and `/api/share` returns the normal unknown-API 404.
91
+
92
+ ---
93
+
94
+ ## Environment Configuration
95
+
96
+ The active Incident Report flow is local and does not require `GEMINI_API_KEY`. Dormant Alpha/API compatibility code remains server-side and retains its existing access configuration. No document-sharing KV binding is required.
97
+
98
+ ---
99
+
100
+ ## Running Locally
101
+
102
+ To run Paper locally with functional API routes:
103
+
104
+ 1. Configure `.dev.vars` with the required local secrets.
105
+
106
+ 2. Start the existing Cloudflare development server:
107
+
108
+ ```bash
109
+ npx.cmd wrangler dev
110
+ ```
111
+
112
+ 3. Open the public landing page at `http://localhost:8787/` or the packet builder at `http://localhost:8787/app/`.
113
+
114
+ For production deployment, always select the production Wrangler environment explicitly:
115
+
116
+ ```bash
117
+ npm.cmd run deploy:production
118
+ ```
119
+
120
+ Running `wrangler deploy` without `--env production` selects the top-level local configuration and its placeholder `ALPHA_DB`; it is not a production deployment command.
121
+
122
+ ## Issuing an Alpha Access Link
123
+
124
+ Use the trusted local issuer for a manually approved tester. It requires only an operator label and defaults to production D1 and `https://paper-ai.paperhq.workers.dev`:
125
+
126
+ ```bash
127
+ npm run alpha:issue -- --label "CJ"
128
+ ```
129
+
130
+ On Windows PowerShell, use `npm.cmd` if execution policy blocks `npm.ps1`. Wrangler must already have production D1 permissions. The label is private metadata, not an account or authentication factor. Reusing a label creates a separate invite; it does not look up a person or modify their previous session.
131
+
132
+ When diagnosing an operational failure, consult the repository's [observed operator error reference](docs/operator-errors.md) before changing the Alpha access implementation.
133
+
134
+ **CJ Protocol** is the pre-send production verification gate: an invite URL is released only after the production Worker confirms that the exact invite is currently redeemable without consuming it. The issuer sends the exact token and returned credential ID to the Worker's same-origin verification route, where the token is hashed and checked through the same active-state validation used before redemption. Only a `204` response writes the complete private URL to stdout. Progress and diagnostics go to stderr, so failed verification leaves stdout empty. Send the URL directly to the tester; do not open it for them or paste it into logs or tickets. It contains a cryptographically random token, with only its hash stored in D1. No email, signup row, Turnstile, or email delivery is involved in manual issuance.
135
+
136
+ Invites expire after **24 hours** and are atomically single-use. The tester clicks **Open Paper** in their chosen browser; merely loading the invitation page does not consume it. Successful redemption creates the existing secure, HttpOnly, SameSite=Lax 30-day session. An already-authorized browser resumes `/app/` without consuming another invitation. Other browsers need their own fresh invite. Re-run the issuer for a replacement if required; it does not revoke existing sessions.
137
+
138
+ ### Release prerequisite
139
+
140
+ Before issuing access to an untrusted tester, follow [Alpha security operations](docs/alpha-security-operations.md): credential-level revocation, migration `0003`, required durable Review ceilings, and production/legacy deployment checks. The issuer prints the credential ID to stderr for operator records; retain it without the bearer link. `npm.cmd run alpha:revoke -- --credential-id <id>` invalidates both the invite and its derived session and confirms the exact row. Labels are not unique identifiers.
141
+
142
+ Before the first label-only production invite, apply `migrations/0002_manual_alpha_invites.sql` through the normal D1 migration workflow, then deploy the matching Worker and assets. The migration rebuilds only the credential child table to permit a label in place of a signup reference, preserving existing credentials and sessions. The new Worker, including `/api/alpha/invite/verify`, must be live before using the updated issuer; an older deployment will make verification fail closed and release no link. Applying this migration or deploying is a separate, explicitly authorized release step.
143
+
144
+ ### Verification
145
+
146
+ `npm test` includes issuer, migration, real SQL storage/Worker, expiry-boundary, concurrency, and authorization tests. `npm run test:alpha-browser` runs the real issuer CLI against temporary local D1, then exercises Chromium, Wrangler, the access page, secure cookie, protected app, replay/expiry rejection, replacement links, session resume, and preservation of existing notes. It also tests the dormant email flow and Turnstile rejection. No production D1 is used.
147
+
148
+ For isolated local testing only, the issuer supports `--local --persist-to <temporary-directory> --origin http://127.0.0.1:<port>`. `--local` never sends a remote D1 command. HTTPS origin and environment overrides remain available for staging; normal production issuance needs neither.
package/dist/paper.js ADDED
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+ import{spawn as B}from"node:child_process";import{createHash as Z}from"node:crypto";import{realpathSync as V}from"node:fs";import{lstat as q,mkdir as P,readFile as K,rename as X,stat as F,writeFile as M}from"node:fs/promises";import{homedir as $,platform as O}from"node:os";import{basename as k,dirname as f,join as o,resolve as g}from"node:path";import{fileURLToPath as Y}from"node:url";var I=[["1. Scope",[["what-failing","What is failing?"],["still-working","What is still working?"],["failure-breadth","How broad is the failure?"],["deterministic","Is it deterministic?"]]],["2. Delta",[["changed-recently","What changed recently?"],["did-not-change","What did not change?"],["git-runtime-environment-differences","Relevant git/runtime/environment differences"]]],["3. Failure Boundary",[["expected-at-boundary","Expected behavior at the boundary"],["observed-at-boundary","Observed behavior at the boundary"],["input-payload","Exact input/payload entering the boundary"],["output-error","Exact output/error leaving the boundary"]]],["4. Execution Path",[["origin","Origin"],["intermediate-components","Intermediate components"],["first-confirmed-divergence","First confirmed divergence"],["runtime-environment-hops","Runtime/environment at relevant hops"]]],["5. Evidence",[["exit-code","Exit code"],["stderr-stack-trace","stderr / stack trace"],["status-codes","Status codes"],["commands","Commands"],["changed-files","Changed files"],["git-diff-stat","git diff/stat"],["runtime-versions","Runtime versions"],["other-receipts","Other deterministic receipts"]]],["6. Falsified Hypotheses",[["hypothesis","Hypothesis"],["test-check","Test/check performed"],["result","Result"],["why-ruled-out","Why it is ruled out"]]],["7. Current Working Hypothesis",[["working-hypothesis","Hypothesis"],["supporting-evidence","Evidence supporting it"],["opposing-evidence","Evidence against it"]]],["8. Next Test",[["smallest-action","Smallest action to isolate or test next"]]]],ke=I.flatMap(([,e])=>e);function R(e={}){let t=I.flatMap(([n,r])=>{let s=r.flatMap(([a,i])=>{let c=String(e[a]??"").trim();return c?[`### ${i}
3
+
4
+ ${c}`]:[]});return s.length?[`## ${n}
5
+
6
+ ${s.join(`
7
+
8
+ `)}`]:[]});return`# Incident Report${t.length?`
9
+
10
+ ${t.join(`
11
+
12
+ `)}`:""}`}var T={name:"@varman96/paper",version:"1.0.0",description:"Paper captures command failures in a structured Incident Report for coding-agent investigation.",main:"dist/paper.js",bin:{paper:"./dist/paper.js"},files:["dist/paper.js","README.md","LICENSE"],directories:{test:"test"},scripts:{"alpha:issue":"node scripts/issue-alpha-access.js","alpha:revoke":"node scripts/revoke-alpha-access.js","fail:test":"node scripts/fail-test.js",paper:"node scripts/paper.js","build:cli":"node scripts/build-cli.js",prepack:"npm run build:cli","deploy:production":"wrangler deploy --env production",test:"node test/run-tests.js","test:fast":"node test/run-tests.js --fast","test:browser":"node test/run-tests.js --browser","test:alpha-browser":"node test/alpha-access.browser.js"},repository:{type:"git",url:"git+https://github.com/varman96/paper.git"},keywords:[],author:"",license:"SEE LICENSE IN LICENSE",type:"module",bugs:{url:"https://github.com/varman96/paper/issues"},homepage:"https://github.com/varman96/paper#readme",devDependencies:{"@biomejs/biome":"2.5.14",esbuild:"^0.28.1",wrangler:"^4.132.0"}};var J=`Paper captures a failed command and writes a local Incident Report.
13
+
14
+ Usage: paper run <command>
15
+
16
+ Examples:
17
+ paper run npm test
18
+ paper run node scripts/build.mjs
19
+
20
+ Report: .paper/incident_report.md
21
+
22
+ paper shelf Move the active Incident Report out of the workspace
23
+
24
+ --help Show this help
25
+ --version Show the version`,y=["<!-- paper:start -->","## Paper Incident Workflow","","When `.paper/incident_report.md` exists, read it before investigating.","","Treat the Incident Report as the current evidence anchor, not as infallible truth. Use it to establish the known failure boundary, then inspect the repository, runtime, tests, configuration, and other source-of-truth evidence as needed.","","Diagnose the issue using this trace:","","### 1. Establish the Failing Invariant","","Identify the exact boundary contract that was violated.","","State:","","Invariant Expected:","The concrete behavior or state that should have held.","","Invariant Observed:","The concrete behavior or state actually observed.","","Use precise system evidence where available:","- exit codes","- status codes","- errno","- ports","- file paths","- symbols","- stack frames","- environment values","- process state","- exact command output","","Do not replace concrete evidence with vague summaries.","","### 2. State Elimination","","Shrink the search space by explicitly ruling out competing explanations using verified evidence.","","For each relevant factor, state whether it is:","- confirmed working","- confirmed failing","- still unverified","","Examples:","- config parsed successfully","- network route reachable","- dependency present or missing","- process listening or not listening","- expected environment variable present or absent","","Do not mark a hypothesis ruled out without evidence.","","Do not repeat theories already ruled out by the Incident Report unless new evidence justifies reopening them.","","### 3. Single-Point Attribution","","Narrow the diagnosis to the smallest confirmed fault boundary.","","State:","","Fault Location:","The exact file, line, symbol, process, dependency, configuration value, environment delta, or runtime boundary responsible.","","Mechanism:","The concrete way that fault caused the observed invariant violation.","","Do not invent a root cause if the evidence only supports a narrower failure boundary.","","If the mechanism is not yet verified, label it as unverified and continue investigating.","","Newer source-of-truth evidence overrides stale or incorrect Incident Report content.","","### 4. Proposed Action Packet \u2014 Zero Execution","","Once the failure is sufficiently explained, STOP before remediation.","","Do not:","- modify files","- start or stop services","- change configuration","- install dependencies","- run a fix","- apply a patch","- mutate the environment","","unless the user explicitly asked for remediation.","","Report:","","What I found:","A concise diagnosis grounded in the Incident Report and verified evidence gathered afterward.","","Proposed fix:","The smallest intervention that addresses the confirmed mechanism.","","Diff preview:","Describe the expected code/config change if applicable. Do not apply it.","","Verification test:","Name the smallest test or command that would verify the proposed fix.","","Clearly distinguish:","- evidence already present in the Incident Report","- findings established during investigation","- hypotheses that remain unverified","","Once the current failure is sufficiently explained, stop widening the investigation unless new evidence connects another issue to the same failure.","","Important behavior:","- The agent may inspect the repo/runtime normally.","- The Incident Report is not the only source of truth.","- The agent must not hallucinate missing telemetry.","- The agent must not convert an unverified hypothesis into a confirmed diagnosis.","- The agent must not execute remediation unless explicitly asked.","- The diagnostic trace is investigative structure, not verbose prose. Keep each section concise and evidence-based.","<!-- paper:end -->"].join(`
26
+ `),d=class extends Error{constructor(t,n,r,s){super(n),this.name="PaperCliError",this.causeLabel=t,this.state=r,this.directive=s}};function N(e){return e instanceof d?[e.causeLabel,e.message,"",e.state,"",e.directive].join(`
27
+ `):["PAPER OPERATION FAILED",e?.message||"Paper encountered an unclassified local operation failure.","","Paper stopped before the requested operation completed.","","Resolve the reported local error and run Paper again."].join(`
28
+ `)}function Q({modulePath:e=Y(import.meta.url),invokedPath:t=process.argv[1],resolvePath:n=V.native}={}){if(!t)return{isCli:!1,startupFailure:!1};try{return{isCli:n(g(e))===n(g(t)),startupFailure:!1}}catch{let r=k(e).toLowerCase(),s=k(t).toLowerCase();return{isCli:!1,startupFailure:r===s}}}async function ee(e){try{let t=await F(e);return t.isDirectory()||t.isFile()}catch{return!1}}async function x(e=process.cwd()){let t=g(e);for(;;){if(await ee(o(t,".git")))return t;let n=f(t);if(n===t)return g(e);t=n}}async function v(e,t){try{let n=await F(e);return t==="directory"?n.isDirectory():t==="file"?n.isFile():!0}catch{return!1}}async function m(e){try{if((await q(e)).isSymbolicLink())throw new Error(`Refusing to write through a symbolic link: ${e}`)}catch(t){if(t.code!=="ENOENT")throw t}}async function te(e){let t=[],n=["AGENTS.md","CLAUDE.md","GEMINI.md",o(".github","copilot-instructions.md"),".cursorrules",o(".cursor","rules.md"),o(".cursor","instructions.md")];for(let r of n)await v(o(e,r),"file")&&t.push(o(e,r));return await v(o(e,".cursor","rules"),"directory")&&t.push(o(e,".cursor","rules","paper.mdc")),t.length?t:[o(e,"AGENTS.md")]}function ne(e){let t=/<!-- paper:start -->[\s\S]*?<!-- paper:end -->/g;if(e.match(t)?.length){let r=0,s=e.replace(t,()=>r++===0?y:"");return{next:s,changed:s!==e}}return{next:e?`${e}${e.endsWith(`
29
+ `)?`
30
+ `:`
31
+
32
+ `}${y}
33
+ `:`${y}
34
+ `,changed:!0}}async function re(e=process.cwd()){let t=await x(e),n=await te(t),r=[],s=[];for(let a of n){await m(a),await m(f(a)),await m(f(f(a)));let i="";try{i=await K(a,"utf8")}catch(u){if(u.code!=="ENOENT")throw u}let{next:c,changed:l}=ne(i);l&&(await P(f(a),{recursive:!0}),await M(a,c,"utf8"),r.push(a),i||s.push(a))}return{repoRoot:t,targetPaths:n,changedPaths:r,created:s.length>0,changed:r.length>0}}async function ie(e,t){let n=o(e,".paper","incident_report.md");return await m(o(e,".paper")),await m(n),await P(f(n),{recursive:!0}),await M(n,t,"utf8"),n}function se(e=process.env,t=O()){return t==="win32"?e.LOCALAPPDATA||o($(),"AppData","Local","Paper"):o(e.XDG_DATA_HOME||o($(),".local","share"),"Paper")}function ae(e,t=process.env,n=O()){let r=Z("sha256").update(g(e)).digest("hex").slice(0,16);return o(se(t,n),"shelf",r)}function oe(e=new Date){return e.toISOString().replace(/[:.]/g,"-")}async function ce(e,t){let n=0;for(;;){let r=o(e,`${t}${n?`-${n}`:""}.md`);if(!await v(r,"file"))return r;n+=1}}async function de(){let e=await x(),t=o(e,".paper","incident_report.md");if(!await v(t,"file"))throw new d("NO ACTIVE INCIDENT","Paper could not find an active Incident Report.","No files were changed.","Run `paper run <command>` to capture a failure first.");let n=ae(e),r=await ce(n,oe());try{await P(n,{recursive:!0}),await X(t,r)}catch(s){throw new d("INCIDENT SHELF FAILED",`Paper could not move the Incident Report out of the workspace${s?.code?` (${s.code})`:"."}`,"The active Incident Report was preserved in the workspace.","Restore access to the Paper shelf location and run `paper shelf` again.")}process.stdout.write(`INCIDENT SHELVED
35
+ Moved the active Incident Report out of the workspace.
36
+
37
+ Stored at:
38
+ ${r}
39
+ `)}function H(e,t){return[e,...t].join(" ")}function pe(e,t,n){return new Promise((r,s)=>{let a=!1,i=B(e,t,{cwd:n,windowsHide:!0,stdio:["inherit","pipe","pipe"]}),c="",l="";i.stdout.on("data",u=>{c+=u}),i.stderr.on("data",u=>{l+=u}),i.once("error",u=>{a||(a=!0,s(u))}),i.once("close",(u,w)=>{a||(a=!0,r({code:u,signal:w,stdout:c,stderr:l}))})})}function ue(e,t,n){let r=n.signal?`Process terminated by signal ${n.signal}`:`Process exited with code ${n.code}`;return[`$ ${H(e,t)}`,n.stdout,n.stderr,r].filter(Boolean).join(`
40
+ `)}function le(e,t){let n=`\`${e}\``;return t?.code==="ENOENT"?new d("BINARY MISSING",`${n} was not found in the active PATH.`,"Execution stopped before the target command started.",`Install ${n} or run Paper with a command that exists in this shell.`):t?.code==="EACCES"?new d("PERMISSION DENIED",`Paper could not execute ${n} from this shell.`,"Execution stopped before the target command started.",`Restore execute permission for ${n} or run Paper with an executable command.`):new d("TARGET START FAILED",`Paper could not start ${n}${t?.message?`: ${t.message}`:"."}`,"Execution stopped before the target command started.",`Run ${n} directly in this shell to verify that it can start, then run Paper again.`)}function he(e,t,n){return new d("REPORT WRITE FAILED",`Paper could not persist the Incident Report at \`${t}\`${e?.code?` (${e.code})`:"."}`,n?"The target command finished, but the report was not persisted.":"Paper stopped before the target command started.","Restore write access to the report location and run Paper again.")}function fe(e){return new d("AGENT RULES WRITE FAILED",`Paper could not update the repository instruction file${e?.code?` (${e.code})`:"."}`,"Execution stopped before the target command started.","Restore write access to the repository instruction file and run Paper again.")}async function me(e,t){let n=await x();try{await re()}catch(i){throw fe(i)}let r;try{r=await pe(e,t,n)}catch(i){throw le(e,i)}let s=o(n,".paper","incident_report.md");r.stdout&&process.stdout.write(r.stdout),r.stderr&&process.stderr.write(r.stderr);let a=`\`${H(e,t)}\``;if(r.code!==0||r.signal){let i=$e(ue(e,t,r));try{await ie(n,i)}catch(l){throw he(l,s,!0)}let c=r.signal?`signal ${r.signal}`:`code ${r.code}`;process.stderr.write(`COMMAND FAILED
41
+ ${a} exited with ${c}.
42
+
43
+ Paper captured the failure and persisted the Incident Report at \`${s}\`.
44
+ `)}}var ge=[/\b(?:error|fatal|exception|panic|failed|failure|traceback|segmentation fault|command not found|exited with code)\b|ERR!/i,/\b(?:HTTP\/\d(?:\.\d)?\s+)?[45]\d{2}\b/i,/\b(?:exit(?:ed| status| code)?|status code)\s*[:=]?\s*[1-9]\d*/i],we=/HTTP\/\d(?:\.\d)?\s+[1-5]\d{2}\b|\bstatus(?: code)?\s*[:=]?\s*[1-5]\d{2}\b/i,ve=/\b(?:exited with code|exit(?: status| code)?|status code)\s*[:=]?\s*[1-9]\d*/i,W=/^\s*(?:at\s+.+|File\s+["'].+["'],\s*line\s+\d+|[\w.]+\.[\w$]+\([^)]*:\d+(?::\d+)?\))/i,_=/^\s*(?:[$>]|(?:curl|wget|git|docker|kubectl|wrangler|npm|npx|node|python(?:\d+)?|pytest|cargo|go|dotnet|java|bun|deno|yarn|pnpm)\b)/i,be=/\b(?:node(?:\.js)?|npm|npx|pnpm|yarn|bun|deno|python(?:\d+)?|pytest|ruby|java|dotnet|cargo|rustc|go version|windows|linux|darwin|macos|runtime|version)\b/i,ye=/(?:[A-Za-z]:[\\/][^\s,;()[\]{}]+|(?:\.{0,2}[\\/])?[A-Za-z0-9_.-]+(?:[\\/][A-Za-z0-9_.-]+)+\.[A-Za-z0-9_.-]+)/g,A=/^\s*(?:\+\s*)?(?:CategoryInfo|FullyQualifiedErrorId)\b/i,S=/^\s*At line:\d+ char:\d+\s*$/i,C=/^\s*(?:\+\s*)?~+\s*$/,D=/^\s*\+\s*npm(?:\.cmd)?\b/i,Pe=/^\s*\+\s*curl(?:\.exe)?\b/i,xe=/^\s*\|\s*(?:node|npm|npx)\b/i,j=/^\s*(?:npm(?:\.cmd)?|curl(?:\.exe)?)\s*:\s+/i,Ee=/^\s*[a-z]:\/\//i;function Ie(e=""){let t=String(e??""),n=t.replace(/\r\n?/g,`
45
+ `).split(`
46
+ `);if(!(n.some(i=>A.test(i))&&n.some(i=>j.test(i))))return t;let s=[],a=!1;for(let i of n){if(A.test(i)){a=!0;continue}if(a){if(!i.trim()){a=!1,s.push(i);continue}if(S.test(i)||C.test(i)||D.test(i))continue;if(W.test(i)||_.test(i))a=!1;else continue}if(S.test(i)||C.test(i)||D.test(i)||xe.test(i))continue;if(Pe.test(i)){let l=i.replace(/^\s*\+\s*/,"");s.at(-1)!==l&&s.push(l);continue}if(Ee.test(i))continue;let c=i.replace(j,"");s.at(-1)!==c&&s.push(c)}return s.join(`
47
+ `)}function h(e){return[...new Set(e.map(t=>t.trim()).filter(Boolean))]}function Re(e){return h([...e.matchAll(ye)].map(([t])=>t.replace(/[.:]+$/,"")).filter(t=>!/^HTTP\/\d(?:\.\d)?$/i.test(t)&&!/^[a-z]:\/\//i.test(t)))}function Te(e=""){let t=Ie(e),r=t.replace(/\r\n?/g,`
48
+ `).split(`
49
+ `).filter(p=>p.trim()),s=h(r.filter(p=>ge.some(G=>G.test(p)))),a=h(r.filter(p=>W.test(p))),i=h(r.filter(p=>_.test(p))),c=h(r.filter(p=>be.test(p))),l=h(r.filter(p=>we.test(p))),u=h(r.filter(p=>ve.test(p))),w=Re(t),E=h([...s,...a]).join(`
50
+ `),b=i.join(`
51
+ `),z=w.length?`${w.join(`
52
+ `)}
53
+
54
+ ${t}`:t;return{"what-failing":s.join(`
55
+ `),"observed-at-boundary":s.join(`
56
+ `),"input-payload":b,"output-error":E,origin:b,"first-confirmed-divergence":s[0]||a[0]||"","runtime-environment-hops":c.join(`
57
+ `),"exit-code":u.join(`
58
+ `),"stderr-stack-trace":E,"status-codes":l.join(`
59
+ `),commands:b,"runtime-versions":c.join(`
60
+ `),"other-receipts":z}}function $e(e=""){return R(Te(e))}var L=Q();if(L.startupFailure)process.stderr.write(`${N(new d("CLI ENTRYPOINT MISMATCH","Paper loaded, but the executable path could not be resolved to the active CLI entrypoint.","No target command was started.","Reinstall or relink Paper and run the command again."))}
61
+ `),process.exitCode=1;else if(L.isCli)try{let e=process.argv.slice(2);if(e[0]==="--help")process.stdout.write(`${J}
62
+ `);else if(e[0]==="--version")process.stdout.write(`${T.version}
63
+ `);else if(e[0]==="shelf"&&e.length===1)await de();else if(e.length){if(e[0]!=="run")throw new d("INVALID COMMAND","Paper expected `run` before the target command.","No target command was started.","Use `paper run <command>`.");if(e.length===1)throw new d("NO COMMAND","Paper needs a command to capture.","No target command was started.","Use `paper run <command>`. ");await me(e[1],e.slice(2))}else throw new d("NO COMMAND","Paper needs a command to capture.","No target command was started.","Use `paper run <command>`.")}catch(e){process.stderr.write(`${N(e)}
64
+ `),process.exitCode=1}export{y as MANAGED_AGENT_RULES_BLOCK,d as PaperCliError,$e as buildTerminalPacket,te as detectAgentInstructionPaths,re as ensureManagedAgentRules,Te as extractTerminalPacket,x as findRepoRoot,N as formatPaperCliError,Ie as normalizeTerminalOutput,Q as resolveCliEntrypoint,ae as shelfPathForRepo,ie as writeIncidentReport};
package/package.json CHANGED
@@ -1,6 +1,47 @@
1
1
  {
2
- "name": "@varman96/paper",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
2
+ "name": "@varman96/paper",
3
+ "version": "1.0.0",
4
+ "description": "Paper captures command failures in a structured Incident Report for coding-agent investigation.",
5
+ "main": "dist/paper.js",
6
+ "bin": {
7
+ "paper": "./dist/paper.js"
8
+ },
9
+ "files": [
10
+ "dist/paper.js",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "directories": {
15
+ "test": "test"
16
+ },
17
+ "scripts": {
18
+ "alpha:issue": "node scripts/issue-alpha-access.js",
19
+ "alpha:revoke": "node scripts/revoke-alpha-access.js",
20
+ "fail:test": "node scripts/fail-test.js",
21
+ "paper": "node scripts/paper.js",
22
+ "build:cli": "node scripts/build-cli.js",
23
+ "prepack": "npm run build:cli",
24
+ "deploy:production": "wrangler deploy --env production",
25
+ "test": "node test/run-tests.js",
26
+ "test:fast": "node test/run-tests.js --fast",
27
+ "test:browser": "node test/run-tests.js --browser",
28
+ "test:alpha-browser": "node test/alpha-access.browser.js"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/varman96/paper.git"
33
+ },
34
+ "keywords": [],
35
+ "author": "",
36
+ "license": "SEE LICENSE IN LICENSE",
37
+ "type": "module",
38
+ "bugs": {
39
+ "url": "https://github.com/varman96/paper/issues"
40
+ },
41
+ "homepage": "https://github.com/varman96/paper#readme",
42
+ "devDependencies": {
43
+ "@biomejs/biome": "2.5.14",
44
+ "esbuild": "^0.28.1",
45
+ "wrangler": "^4.132.0"
46
+ }
47
+ }