gipity 1.0.48

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 (116) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +234 -0
  3. package/dist/__tests__/config.test.d.ts +1 -0
  4. package/dist/__tests__/config.test.js +31 -0
  5. package/dist/__tests__/config.test.js.map +1 -0
  6. package/dist/__tests__/sync.test.d.ts +1 -0
  7. package/dist/__tests__/sync.test.js +89 -0
  8. package/dist/__tests__/sync.test.js.map +1 -0
  9. package/dist/__tests__/utils.test.d.ts +1 -0
  10. package/dist/__tests__/utils.test.js +69 -0
  11. package/dist/__tests__/utils.test.js.map +1 -0
  12. package/dist/api.d.ts +13 -0
  13. package/dist/api.js +85 -0
  14. package/dist/api.js.map +1 -0
  15. package/dist/auth.d.ts +12 -0
  16. package/dist/auth.js +90 -0
  17. package/dist/auth.js.map +1 -0
  18. package/dist/coding-guidelines.d.ts +9 -0
  19. package/dist/coding-guidelines.js +52 -0
  20. package/dist/coding-guidelines.js.map +1 -0
  21. package/dist/commands/agent.d.ts +2 -0
  22. package/dist/commands/agent.js +164 -0
  23. package/dist/commands/agent.js.map +1 -0
  24. package/dist/commands/api.d.ts +2 -0
  25. package/dist/commands/api.js +137 -0
  26. package/dist/commands/api.js.map +1 -0
  27. package/dist/commands/audit.d.ts +2 -0
  28. package/dist/commands/audit.js +70 -0
  29. package/dist/commands/audit.js.map +1 -0
  30. package/dist/commands/browser.d.ts +2 -0
  31. package/dist/commands/browser.js +88 -0
  32. package/dist/commands/browser.js.map +1 -0
  33. package/dist/commands/chat.d.ts +2 -0
  34. package/dist/commands/chat.js +68 -0
  35. package/dist/commands/chat.js.map +1 -0
  36. package/dist/commands/checkpoint.d.ts +2 -0
  37. package/dist/commands/checkpoint.js +67 -0
  38. package/dist/commands/checkpoint.js.map +1 -0
  39. package/dist/commands/credits.d.ts +2 -0
  40. package/dist/commands/credits.js +57 -0
  41. package/dist/commands/credits.js.map +1 -0
  42. package/dist/commands/db.d.ts +2 -0
  43. package/dist/commands/db.js +102 -0
  44. package/dist/commands/db.js.map +1 -0
  45. package/dist/commands/deploy.d.ts +2 -0
  46. package/dist/commands/deploy.js +49 -0
  47. package/dist/commands/deploy.js.map +1 -0
  48. package/dist/commands/file.d.ts +2 -0
  49. package/dist/commands/file.js +85 -0
  50. package/dist/commands/file.js.map +1 -0
  51. package/dist/commands/fn.d.ts +2 -0
  52. package/dist/commands/fn.js +87 -0
  53. package/dist/commands/fn.js.map +1 -0
  54. package/dist/commands/init.d.ts +2 -0
  55. package/dist/commands/init.js +107 -0
  56. package/dist/commands/init.js.map +1 -0
  57. package/dist/commands/login.d.ts +2 -0
  58. package/dist/commands/login.js +62 -0
  59. package/dist/commands/login.js.map +1 -0
  60. package/dist/commands/logout.d.ts +2 -0
  61. package/dist/commands/logout.js +14 -0
  62. package/dist/commands/logout.js.map +1 -0
  63. package/dist/commands/logs.d.ts +2 -0
  64. package/dist/commands/logs.js +39 -0
  65. package/dist/commands/logs.js.map +1 -0
  66. package/dist/commands/memory.d.ts +2 -0
  67. package/dist/commands/memory.js +114 -0
  68. package/dist/commands/memory.js.map +1 -0
  69. package/dist/commands/project.d.ts +2 -0
  70. package/dist/commands/project.js +132 -0
  71. package/dist/commands/project.js.map +1 -0
  72. package/dist/commands/push.d.ts +2 -0
  73. package/dist/commands/push.js +34 -0
  74. package/dist/commands/push.js.map +1 -0
  75. package/dist/commands/rbac.d.ts +2 -0
  76. package/dist/commands/rbac.js +89 -0
  77. package/dist/commands/rbac.js.map +1 -0
  78. package/dist/commands/records.d.ts +2 -0
  79. package/dist/commands/records.js +131 -0
  80. package/dist/commands/records.js.map +1 -0
  81. package/dist/commands/sandbox.d.ts +2 -0
  82. package/dist/commands/sandbox.js +53 -0
  83. package/dist/commands/sandbox.js.map +1 -0
  84. package/dist/commands/scaffold.d.ts +2 -0
  85. package/dist/commands/scaffold.js +38 -0
  86. package/dist/commands/scaffold.js.map +1 -0
  87. package/dist/commands/start-cc.d.ts +2 -0
  88. package/dist/commands/start-cc.js +201 -0
  89. package/dist/commands/start-cc.js.map +1 -0
  90. package/dist/commands/status.d.ts +2 -0
  91. package/dist/commands/status.js +43 -0
  92. package/dist/commands/status.js.map +1 -0
  93. package/dist/commands/sync.d.ts +2 -0
  94. package/dist/commands/sync.js +42 -0
  95. package/dist/commands/sync.js.map +1 -0
  96. package/dist/commands/workflow.d.ts +2 -0
  97. package/dist/commands/workflow.js +163 -0
  98. package/dist/commands/workflow.js.map +1 -0
  99. package/dist/config.d.ts +15 -0
  100. package/dist/config.js +76 -0
  101. package/dist/config.js.map +1 -0
  102. package/dist/index.d.ts +2 -0
  103. package/dist/index.js +65 -0
  104. package/dist/index.js.map +1 -0
  105. package/dist/setup.d.ts +23 -0
  106. package/dist/setup.js +168 -0
  107. package/dist/setup.js.map +1 -0
  108. package/dist/sync.d.ts +34 -0
  109. package/dist/sync.js +234 -0
  110. package/dist/sync.js.map +1 -0
  111. package/dist/utils.d.ts +10 -0
  112. package/dist/utils.js +57 -0
  113. package/dist/utils.js.map +1 -0
  114. package/hooks/post-write.sh +17 -0
  115. package/hooks/pre-turn.sh +20 -0
  116. package/package.json +29 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Gipity
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,234 @@
1
+ # Gipity CLI
2
+
3
+ Connect AI coding agents to the Gipity platform. Built for [Claude Code](https://claude.ai/claude-code) and works great from your terminal too.
4
+
5
+ Gipity gives your AI agent a persistent workspace with file storage, databases, code execution, deployment, memory, workflows, and more. This CLI is the bridge.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install -g @gipity/cli
11
+ ```
12
+
13
+ Requires Node 18+.
14
+
15
+ ## Quick Start
16
+
17
+ One command. It walks you through login, project setup, and drops you into Claude Code.
18
+
19
+ ```bash
20
+ gipity start-cc --dangerously-skip-permissions
21
+ ```
22
+
23
+ That's it. You'll see:
24
+
25
+ ```
26
+ Welcome to Gipity
27
+ ─────────────────
28
+
29
+ Email: you@example.com
30
+ Check your email for a 6-digit code.
31
+
32
+ Code: 482910
33
+ Authenticated as you@example.com
34
+
35
+ Your projects:
36
+ 1. my-website (my-website)
37
+ 2. Create new project
38
+
39
+ Choose (1-2): 2
40
+ Project name [project01]: cool-app
41
+ Creating "cool-app"...
42
+ Created.
43
+
44
+ Launching Claude Code...
45
+ ```
46
+
47
+ If you're already logged in, it skips straight to project setup. If you already have a project in the current directory, it skips straight to launching Claude Code.
48
+
49
+ Projects live in `~/GipityProjects/{project-slug}/` — created automatically on first use. Any extra flags (like `--dangerously-skip-permissions`, `--model opus`, etc.) get passed through to Claude.
50
+
51
+ ### The manual way
52
+
53
+ If you prefer to do things step by step:
54
+
55
+ ```bash
56
+ gipity login --email you@example.com
57
+ gipity login --code 123456
58
+ cd my-project
59
+ gipity init
60
+ claude
61
+ ```
62
+
63
+ ## Claude Code Integration
64
+
65
+ This is the good part. When you run `gipity init` in a project, it sets up two hooks in `.claude/settings.json`:
66
+
67
+ **Auto-push** — Every time Claude Code writes or edits a file, it gets pushed to Gipity in the background. No extra steps.
68
+
69
+ **Auto-pull** — Before each turn, Claude Code pulls any changes that happened remotely (like if your Gipity agent built something via chat). Claude sees what changed and can pick up where things left off.
70
+
71
+ That means Claude Code and your Gipity agent share the same files, same project, same context. You get the best of both — Claude Code for hands-on coding, Gipity for autonomous agent work.
72
+
73
+ ### What gets set up
74
+
75
+ ```
76
+ .gipity.json # Project config (which project, which agent)
77
+ .gipity/ # Local sync state (gitignored)
78
+ .claude/settings.json # Hooks for auto-push and auto-pull
79
+ CLAUDE.md # Gipity commands reference for Claude Code
80
+ ```
81
+
82
+ ### Manual sync
83
+
84
+ If you ever need to sync manually:
85
+
86
+ ```bash
87
+ gipity sync check # See what's different
88
+ gipity sync up # Push local changes
89
+ gipity sync down # Pull remote changes
90
+ ```
91
+
92
+ ## Commands
93
+
94
+ | Command | What it does |
95
+ |---------|-------------|
96
+ | `gipity start-cc` | Log in, pick a project, and launch Claude Code — all in one |
97
+ | `gipity login` | Authenticate with email + verification code |
98
+ | `gipity init` | Set up a Gipity project and configure Claude Code |
99
+ | `gipity status` | Show project, agent, and auth info |
100
+ | `gipity sync` | Sync files between local and Gipity |
101
+ | `gipity push <file>` | Push a single file |
102
+ | `gipity deploy [dev\|prod]` | Deploy your project to the web |
103
+ | `gipity chat <message>` | Send a message to your Gipity agent |
104
+ | `gipity db` | Query, list, or create project databases |
105
+ | `gipity memory` | Read/write agent and project memory |
106
+ | `gipity sandbox run <code>` | Execute code in a sandboxed container |
107
+ | `gipity api` | Define and manage API procedures |
108
+ | `gipity project` | List, create, switch, or delete projects |
109
+ | `gipity agent` | List, create, switch, or configure agents |
110
+ | `gipity workflow` | Manage and trigger automated workflows |
111
+ | `gipity file` | Browse remote files (ls, cat, tree) |
112
+ | `gipity scaffold [title]` | Create web app structure (HTML, CSS, JS, favicons) |
113
+ | `gipity checkpoint` | List or restore file snapshots (undo) |
114
+ | `gipity logs fn <name>` | View function execution logs |
115
+ | `gipity browser <url>` | Inspect a URL: console errors, performance, failed resources |
116
+ | `gipity records` | Query and manage Records API tables |
117
+ | `gipity fn` | Manage and call sandboxed functions |
118
+ | `gipity rbac` | Manage RBAC policies |
119
+ | `gipity audit` | Query audit logs |
120
+ | `gipity credits` | Check your balance and usage |
121
+
122
+ Every command supports `--json` for scripted/programmatic use.
123
+
124
+ ### deploy
125
+
126
+ ```bash
127
+ gipity deploy # Deploy to dev (dev.gipity.ai)
128
+ gipity deploy prod # Deploy to production (app.gipity.ai)
129
+ ```
130
+
131
+ Your project gets a live URL at `https://dev.gipity.ai/{account}/{project}/`.
132
+
133
+ ### chat
134
+
135
+ Talk to your Gipity agent from the terminal. If the agent creates or modifies files, they sync back automatically.
136
+
137
+ ```bash
138
+ gipity chat "Build me a landing page"
139
+ gipity chat "Add a contact form" --new # Start a fresh conversation
140
+ ```
141
+
142
+ ### db
143
+
144
+ ```bash
145
+ gipity db list
146
+ gipity db query "SELECT * FROM users LIMIT 10"
147
+ gipity db query "SELECT * FROM orders" --database my_app_db
148
+ ```
149
+
150
+ ### memory
151
+
152
+ Agent memory persists across all conversations. Project memory is scoped to one project.
153
+
154
+ ```bash
155
+ gipity memory list
156
+ gipity memory read preferences
157
+ gipity memory write api_keys "stripe: sk_live_..."
158
+ gipity memory write design_notes "use dark theme" --project
159
+ ```
160
+
161
+ ### sandbox
162
+
163
+ Run code in a sandboxed Docker container with no network access. JavaScript, Python, and Bash.
164
+
165
+ ```bash
166
+ gipity sandbox run "console.log('Hello')"
167
+ gipity sandbox run "import pandas; print(pandas.__version__)" --lang py
168
+ gipity sandbox run "echo hello" --lang bash
169
+ ```
170
+
171
+ ### api
172
+
173
+ Define SQL-backed API endpoints that your deployed apps can call.
174
+
175
+ ```bash
176
+ gipity api list
177
+ gipity api define get_users --sql "SELECT * FROM users" --database mydb --auth public
178
+ gipity api define create_post --sql @queries/create_post.sql --database mydb --method write
179
+ ```
180
+
181
+ ### workflow
182
+
183
+ ```bash
184
+ gipity workflow # List workflows
185
+ gipity workflow run daily_report # Trigger manually
186
+ gipity workflow enable daily_report # Turn on cron schedule
187
+ gipity workflow runs daily_report # View recent runs
188
+ ```
189
+
190
+ ### agent
191
+
192
+ ```bash
193
+ gipity agent # List agents
194
+ gipity agent create "Research Bot" # Create a new agent
195
+ gipity agent set model claude-opus # Change the model
196
+ gipity agent "Research Bot" # Switch active agent
197
+ ```
198
+
199
+ ### project
200
+
201
+ ```bash
202
+ gipity project # List projects
203
+ gipity project create "My App" # Create new project
204
+ gipity project my-app # Switch active project
205
+ ```
206
+
207
+ ## Project Config
208
+
209
+ ### `.gipity.json`
210
+
211
+ Created by `gipity init`. Links your local directory to a Gipity project.
212
+
213
+ ```json
214
+ {
215
+ "projectGuid": "prj-a1b2c3d4",
216
+ "projectSlug": "my-app",
217
+ "accountSlug": "steve",
218
+ "agentGuid": "agt-x1y2z3w4",
219
+ "apiBase": "https://a.gipity.ai",
220
+ "ignore": ["node_modules", ".git", "dist", ".env"]
221
+ }
222
+ ```
223
+
224
+ ### `~/.gipity/auth.json`
225
+
226
+ Your login tokens. Created by `gipity login`. Tokens auto-refresh so you shouldn't need to log in again unless you've been away for a week.
227
+
228
+ ## Questions?
229
+
230
+ Reach out anytime — steve@gipity.ai
231
+
232
+ This is early and moving fast. If something's broken or confusing, I want to hear about it.
233
+
234
+ -- Steve Iverson
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,31 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { shouldIgnore } from '../config.js';
4
+ describe('shouldIgnore', () => {
5
+ const patterns = ['node_modules', '.git', '.gipity.json', '.gipity/', '.claude/', '*.log'];
6
+ it('ignores exact match', () => {
7
+ assert.equal(shouldIgnore('.gipity.json', patterns), true);
8
+ });
9
+ it('ignores directory name anywhere in path', () => {
10
+ assert.equal(shouldIgnore('node_modules', patterns), true);
11
+ assert.equal(shouldIgnore('src/node_modules/foo.js', patterns), true);
12
+ assert.equal(shouldIgnore('.git', patterns), true);
13
+ });
14
+ it('ignores prefix match with trailing slash', () => {
15
+ assert.equal(shouldIgnore('.gipity/sync-state.json', patterns), true);
16
+ assert.equal(shouldIgnore('.claude/settings.json', patterns), true);
17
+ });
18
+ it('ignores extension match', () => {
19
+ assert.equal(shouldIgnore('app.log', patterns), true);
20
+ assert.equal(shouldIgnore('logs/error.log', patterns), true);
21
+ });
22
+ it('does not ignore non-matching paths', () => {
23
+ assert.equal(shouldIgnore('src/index.ts', patterns), false);
24
+ assert.equal(shouldIgnore('package.json', patterns), false);
25
+ assert.equal(shouldIgnore('README.md', patterns), false);
26
+ });
27
+ it('handles empty patterns', () => {
28
+ assert.equal(shouldIgnore('anything.ts', []), false);
29
+ });
30
+ });
31
+ //# sourceMappingURL=config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.test.js","sourceRoot":"","sources":["../../src/__tests__/config.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,MAAM,QAAQ,GAAG,CAAC,cAAc,EAAE,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;IAE3F,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,cAAc,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,cAAc,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;QAC3D,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,yBAAyB,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;QACtE,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,yBAAyB,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;QACtE,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,uBAAuB,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACjC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;QACtD,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,gBAAgB,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,cAAc,EAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;QAC5D,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,cAAc,EAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;QAC5D,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,aAAa,EAAE,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,89 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { diffManifest, formatDiff } from '../sync.js';
4
+ const remoteFiles = [
5
+ { path: 'src/index.html', size: 500, modified: '2024-01-01', type: 'file', guid: 'f1' },
6
+ { path: 'src/app.js', size: 1200, modified: '2024-01-01', type: 'file', guid: 'f2' },
7
+ { path: 'src/styles.css', size: 300, modified: '2024-01-01', type: 'file', guid: 'f3' },
8
+ { path: 'src/', size: 0, modified: '2024-01-01', type: 'directory', guid: 'd1' },
9
+ ];
10
+ describe('diffManifest — down', () => {
11
+ it('detects added files (remote has, local lacks)', () => {
12
+ const local = new Map();
13
+ const changes = diffManifest(remoteFiles, local, 'down');
14
+ const added = changes.filter(c => c.type === 'added');
15
+ assert.equal(added.length, 3);
16
+ });
17
+ it('detects modified files (size mismatch)', () => {
18
+ const local = new Map([
19
+ ['src/index.html', { size: 999, modified: '2024-01-01' }],
20
+ ['src/app.js', { size: 1200, modified: '2024-01-01' }],
21
+ ['src/styles.css', { size: 300, modified: '2024-01-01' }],
22
+ ]);
23
+ const changes = diffManifest(remoteFiles, local, 'down');
24
+ assert.equal(changes.length, 1);
25
+ assert.equal(changes[0].type, 'modified');
26
+ assert.equal(changes[0].path, 'src/index.html');
27
+ });
28
+ it('detects deleted files (local has, remote lacks)', () => {
29
+ const local = new Map([
30
+ ['src/index.html', { size: 500, modified: '2024-01-01' }],
31
+ ['src/app.js', { size: 1200, modified: '2024-01-01' }],
32
+ ['src/styles.css', { size: 300, modified: '2024-01-01' }],
33
+ ['src/old.js', { size: 100, modified: '2024-01-01' }],
34
+ ]);
35
+ const changes = diffManifest(remoteFiles, local, 'down');
36
+ const deleted = changes.filter(c => c.type === 'deleted');
37
+ assert.equal(deleted.length, 1);
38
+ assert.equal(deleted[0].path, 'src/old.js');
39
+ });
40
+ it('returns empty when in sync', () => {
41
+ const local = new Map([
42
+ ['src/index.html', { size: 500, modified: '2024-01-01' }],
43
+ ['src/app.js', { size: 1200, modified: '2024-01-01' }],
44
+ ['src/styles.css', { size: 300, modified: '2024-01-01' }],
45
+ ]);
46
+ const changes = diffManifest(remoteFiles, local, 'down');
47
+ assert.equal(changes.length, 0);
48
+ });
49
+ });
50
+ describe('diffManifest — up', () => {
51
+ it('detects locally added files', () => {
52
+ const local = new Map([
53
+ ['src/index.html', { size: 500, modified: '2024-01-01' }],
54
+ ['src/app.js', { size: 1200, modified: '2024-01-01' }],
55
+ ['src/styles.css', { size: 300, modified: '2024-01-01' }],
56
+ ['src/new.js', { size: 200, modified: '2024-01-01' }],
57
+ ]);
58
+ const changes = diffManifest(remoteFiles, local, 'up');
59
+ const added = changes.filter(c => c.type === 'added');
60
+ assert.equal(added.length, 1);
61
+ assert.equal(added[0].path, 'src/new.js');
62
+ });
63
+ it('detects locally deleted files', () => {
64
+ const local = new Map([
65
+ ['src/index.html', { size: 500, modified: '2024-01-01' }],
66
+ ]);
67
+ const changes = diffManifest(remoteFiles, local, 'up');
68
+ const deleted = changes.filter(c => c.type === 'deleted');
69
+ assert.equal(deleted.length, 2); // app.js and styles.css
70
+ });
71
+ });
72
+ describe('formatDiff', () => {
73
+ it('returns no changes message when empty', () => {
74
+ assert.equal(formatDiff([], 'down'), 'No changes detected.');
75
+ });
76
+ it('formats changes with counts', () => {
77
+ const changes = [
78
+ { type: 'added', path: 'src/new.js', remoteSize: 100 },
79
+ { type: 'modified', path: 'src/app.js', localSize: 1000, remoteSize: 1200 },
80
+ { type: 'deleted', path: 'src/old.js', localSize: 50 },
81
+ ];
82
+ const output = formatDiff(changes, 'down');
83
+ assert.ok(output.includes('3 changes'));
84
+ assert.ok(output.includes('+ src/new.js'));
85
+ assert.ok(output.includes('~ src/app.js'));
86
+ assert.ok(output.includes('- src/old.js'));
87
+ });
88
+ });
89
+ //# sourceMappingURL=sync.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.test.js","sourceRoot":"","sources":["../../src/__tests__/sync.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAmB,MAAM,YAAY,CAAC;AAEvE,MAAM,WAAW,GAAG;IAClB,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE;IACvF,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE;IACpF,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE;IACvF,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE;CACjF,CAAC;AAEF,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,KAAK,GAAG,IAAI,GAAG,EAA8C,CAAC;QACpE,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QACzD,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;QACtD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC;YACpB,CAAC,gBAAgB,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;YACzD,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;YACtD,CAAC,gBAAgB,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;SAC1D,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QACzD,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAC1C,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC;YACpB,CAAC,gBAAgB,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;YACzD,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;YACtD,CAAC,gBAAgB,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;YACzD,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;SACtD,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QACzD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;QAC1D,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC;YACpB,CAAC,gBAAgB,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;YACzD,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;YACtD,CAAC,gBAAgB,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;SAC1D,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QACzD,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC;YACpB,CAAC,gBAAgB,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;YACzD,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;YACtD,CAAC,gBAAgB,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;YACzD,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;SACtD,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QACvD,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;QACtD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC;YACpB,CAAC,gBAAgB,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;SAC1D,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QACvD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;QAC1D,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,wBAAwB;IAC3D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,sBAAsB,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,OAAO,GAAiB;YAC5B,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,GAAG,EAAE;YACtD,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;YAC3E,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,EAAE,EAAE;SACvD,CAAC;QACF,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC3C,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,69 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { decodeJwtExp, isBinaryFile, formatSize, formatAge } from '../utils.js';
4
+ describe('decodeJwtExp', () => {
5
+ it('extracts exp from a valid JWT', () => {
6
+ // Header: {"alg":"HS256"}, Payload: {"exp":1700000000}, Signature: fake
7
+ const header = Buffer.from('{"alg":"HS256"}').toString('base64url');
8
+ const payload = Buffer.from('{"exp":1700000000}').toString('base64url');
9
+ const token = `${header}.${payload}.fakesig`;
10
+ assert.equal(decodeJwtExp(token), 1700000000);
11
+ });
12
+ it('returns null for malformed token', () => {
13
+ assert.equal(decodeJwtExp('not.a.jwt'), null);
14
+ assert.equal(decodeJwtExp(''), null);
15
+ assert.equal(decodeJwtExp('onlyone'), null);
16
+ });
17
+ it('returns null when exp is missing', () => {
18
+ const header = Buffer.from('{"alg":"HS256"}').toString('base64url');
19
+ const payload = Buffer.from('{"sub":"user"}').toString('base64url');
20
+ const token = `${header}.${payload}.fakesig`;
21
+ assert.equal(decodeJwtExp(token), null);
22
+ });
23
+ });
24
+ describe('isBinaryFile', () => {
25
+ it('detects binary files (null bytes)', () => {
26
+ const buf = Buffer.from([0x48, 0x65, 0x00, 0x6c, 0x6f]);
27
+ assert.equal(isBinaryFile(buf), true);
28
+ });
29
+ it('detects text files', () => {
30
+ const buf = Buffer.from('Hello, world!', 'utf-8');
31
+ assert.equal(isBinaryFile(buf), false);
32
+ });
33
+ it('handles empty buffer', () => {
34
+ assert.equal(isBinaryFile(Buffer.alloc(0)), false);
35
+ });
36
+ });
37
+ describe('formatSize', () => {
38
+ it('formats bytes', () => {
39
+ assert.equal(formatSize(0), '0 B');
40
+ assert.equal(formatSize(512), '512 B');
41
+ assert.equal(formatSize(1023), '1023 B');
42
+ });
43
+ it('formats kilobytes', () => {
44
+ assert.equal(formatSize(1024), '1.0 KB');
45
+ assert.equal(formatSize(1536), '1.5 KB');
46
+ });
47
+ it('formats megabytes', () => {
48
+ assert.equal(formatSize(1048576), '1.0 MB');
49
+ assert.equal(formatSize(2621440), '2.5 MB');
50
+ });
51
+ });
52
+ describe('formatAge', () => {
53
+ it('returns "just now" for recent timestamps', () => {
54
+ assert.equal(formatAge(new Date().toISOString()), 'just now');
55
+ });
56
+ it('returns minutes ago', () => {
57
+ const fiveMinAgo = new Date(Date.now() - 5 * 60 * 1000).toISOString();
58
+ assert.equal(formatAge(fiveMinAgo), '5m ago');
59
+ });
60
+ it('returns hours ago', () => {
61
+ const threeHoursAgo = new Date(Date.now() - 3 * 60 * 60 * 1000).toISOString();
62
+ assert.equal(formatAge(threeHoursAgo), '3h ago');
63
+ });
64
+ it('returns days ago', () => {
65
+ const twoDaysAgo = new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString();
66
+ assert.equal(formatAge(twoDaysAgo), '2d ago');
67
+ });
68
+ });
69
+ //# sourceMappingURL=utils.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.test.js","sourceRoot":"","sources":["../../src/__tests__/utils.test.ts"],"names":[],"mappings":"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"}
package/dist/api.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ export declare class ApiError extends Error {
2
+ statusCode: number;
3
+ code: string;
4
+ constructor(statusCode: number, code: string, message: string);
5
+ }
6
+ export declare function get<T>(path: string): Promise<T>;
7
+ export declare function post<T>(path: string, body?: unknown): Promise<T>;
8
+ export declare function put<T>(path: string, body?: unknown): Promise<T>;
9
+ export declare function del<T>(path: string, body?: unknown): Promise<T>;
10
+ /** Send a message via the conversation API, reusing or creating a conversation. Returns content string. */
11
+ export declare function sendMessage(message: string): Promise<string>;
12
+ /** Unauthenticated request (for login/verify) */
13
+ export declare function publicPost<T>(path: string, body: unknown): Promise<T>;
package/dist/api.js ADDED
@@ -0,0 +1,85 @@
1
+ import { getAuth, refreshTokenIfNeeded } from './auth.js';
2
+ import { getConfig, requireConfig, saveConfig } from './config.js';
3
+ export class ApiError extends Error {
4
+ statusCode;
5
+ code;
6
+ constructor(statusCode, code, message) {
7
+ super(message);
8
+ this.statusCode = statusCode;
9
+ this.code = code;
10
+ this.name = 'ApiError';
11
+ }
12
+ }
13
+ async function getHeaders() {
14
+ await refreshTokenIfNeeded();
15
+ const auth = getAuth();
16
+ if (!auth)
17
+ throw new Error('Not authenticated. Run: gipity login');
18
+ return {
19
+ 'Authorization': `Bearer ${auth.accessToken}`,
20
+ 'Content-Type': 'application/json',
21
+ };
22
+ }
23
+ function baseUrl() {
24
+ const config = getConfig();
25
+ return config?.apiBase || 'https://a.gipity.ai';
26
+ }
27
+ async function request(method, path, body) {
28
+ const headers = await getHeaders();
29
+ const url = `${baseUrl()}${path}`;
30
+ const res = await fetch(url, {
31
+ method,
32
+ headers,
33
+ body: body ? JSON.stringify(body) : undefined,
34
+ });
35
+ if (!res.ok) {
36
+ const json = await res.json().catch(() => ({ error: { code: 'UNKNOWN', message: res.statusText } }));
37
+ const err = json.error || { code: 'UNKNOWN', message: res.statusText };
38
+ throw new ApiError(res.status, err.code, err.message);
39
+ }
40
+ return res.json();
41
+ }
42
+ export function get(path) {
43
+ return request('GET', path);
44
+ }
45
+ export function post(path, body) {
46
+ return request('POST', path, body);
47
+ }
48
+ export function put(path, body) {
49
+ return request('PUT', path, body);
50
+ }
51
+ export function del(path, body) {
52
+ return request('DELETE', path, body);
53
+ }
54
+ /** Send a message via the conversation API, reusing or creating a conversation. Returns content string. */
55
+ export async function sendMessage(message) {
56
+ const config = requireConfig();
57
+ const useExisting = !!config.conversationGuid;
58
+ const endpoint = useExisting
59
+ ? `/conversations/${config.conversationGuid}/messages`
60
+ : '/conversations';
61
+ const body = useExisting
62
+ ? { content: message }
63
+ : { agentGuid: config.agentGuid, content: message, projectGuid: config.projectGuid };
64
+ const res = await post(endpoint, body);
65
+ if (res.data.conversationGuid !== config.conversationGuid) {
66
+ saveConfig({ ...config, conversationGuid: res.data.conversationGuid });
67
+ }
68
+ return res.data.content;
69
+ }
70
+ /** Unauthenticated request (for login/verify) */
71
+ export async function publicPost(path, body) {
72
+ const url = `${baseUrl()}${path}`;
73
+ const res = await fetch(url, {
74
+ method: 'POST',
75
+ headers: { 'Content-Type': 'application/json' },
76
+ body: JSON.stringify(body),
77
+ });
78
+ if (!res.ok) {
79
+ const json = await res.json().catch(() => ({ error: { code: 'UNKNOWN', message: res.statusText } }));
80
+ const err = json.error || { code: 'UNKNOWN', message: res.statusText };
81
+ throw new ApiError(res.status, err.code, err.message);
82
+ }
83
+ return res.json();
84
+ }
85
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
package/dist/auth.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ export interface AuthData {
2
+ accessToken: string;
3
+ refreshToken: string;
4
+ email: string;
5
+ expiresAt: string;
6
+ }
7
+ export declare function getAuth(): AuthData | null;
8
+ export declare function saveAuth(data: AuthData): void;
9
+ export declare function clearAuth(): void;
10
+ export declare function isExpired(): boolean;
11
+ export declare function getTimeRemaining(): string;
12
+ export declare function refreshTokenIfNeeded(): Promise<void>;